/*
 Navicat Premium Data Transfer

 Source Server         : docker_mysql
 Source Server Type    : MySQL
 Source Server Version : 50731
 Source Host           : 127.0.0.1:3306
 Source Schema         : gaoblog

 Target Server Type    : MySQL
 Target Server Version : 50731
 File Encoding         : 65001

 Date: 02/11/2020 16:20:08
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for admin_module
-- ----------------------------
DROP TABLE IF EXISTS `admin_module`;
CREATE TABLE `admin_module` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `pid` int(11) DEFAULT '0' COMMENT '上级模块ID 0为顶级模块',
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '模块名称',
  `url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'url',
  `route_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '路由名称',
  `sonata_admin` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'sonata_admin 服务标签',
  `sort` int(11) DEFAULT '0' COMMENT '排序',
  `icon` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT 'fa fa-angle-double-right' COMMENT 'icon图标',
  `status` tinyint(1) DEFAULT '1' COMMENT '状态 0停用 1启用',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统模块表';

-- ----------------------------
-- Records of admin_module
-- ----------------------------
BEGIN;
INSERT INTO `admin_module` VALUES (1, 0, '用户管理', NULL, NULL, NULL, 4, 'fa fa-users', 1);
INSERT INTO `admin_module` VALUES (2, 1, '用户', '/admin/admin_user/list', 'admin_admin_user_list', '[\"admin.admin_user\"]', 1, 'fa fa-user', 1);
INSERT INTO `admin_module` VALUES (3, 1, '用户组', '/admin/admin_user_group/list', 'admin_admin_user_group_list', '[\"admin.admin_user_group\"]', 2, 'fa fa-users', 1);
INSERT INTO `admin_module` VALUES (5, 0, '文章相关', NULL, NULL, NULL, 1, 'fa fa-file-text-o', 1);
INSERT INTO `admin_module` VALUES (6, 5, '标签', '/admin/page_tag/list', 'admin_page_tag_list', '[\"admin.page_tag\"]', 1, 'fa fa-tags', 1);
INSERT INTO `admin_module` VALUES (7, 5, '类别', '/admin/page_category/list', 'admin_page_category_list', '[\"admin.page_category\"]', 2, 'fa fa-bars', 1);
INSERT INTO `admin_module` VALUES (8, 5, '文章', '/admin/page/list', 'admin_page_list', '[\"admin.page\"]', 3, 'fa fa-file-text', 1);
INSERT INTO `admin_module` VALUES (9, 0, '留言反馈', NULL, NULL, NULL, 2, 'fa fa-comments-o', 1);
INSERT INTO `admin_module` VALUES (10, 9, '评论', '/admin/page_comment/list', 'admin_page_comment_list', '[\"admin.page_comment\"]', 1, 'fa fa-comment', 1);
INSERT INTO `admin_module` VALUES (11, 9, '留言', '/admin/feedback/list', 'admin_feedback_list', '[\"admin.feedback\"]', 2, 'fa fa-envelope', 1);
INSERT INTO `admin_module` VALUES (12, 0, '周边管理', NULL, NULL, NULL, 3, 'fa fa-object-group', 1);
INSERT INTO `admin_module` VALUES (13, 12, '菜单', '/admin/menu/list', 'admin_menu_list', '[\"admin.menu\"]', 1, 'fa fa-map-signs', 1);
INSERT INTO `admin_module` VALUES (15, 0, '系统相关', NULL, NULL, NULL, 5, 'fa fa-gears', 1);
INSERT INTO `admin_module` VALUES (16, 15, '日志', '/admin/log/list', 'admin_log_list', '[\"admin.log\"]', 2, 'fa fa-file', 1);
INSERT INTO `admin_module` VALUES (17, 15, '设置', '/admin/setting/list', 'admin_setting_list', '[\"admin.setting\"]', 1, 'fa fa-gear', 1);
INSERT INTO `admin_module` VALUES (18, 12, '订阅', '/admin/subscribe/list', 'admin_subscribe_list', '[\"admin.subscribe\"]', 2, 'fa fa-envelope-square', 1);
INSERT INTO `admin_module` VALUES (19, 12, '图集', '/admin/gallery/list', 'admin_gallery_list', '[\"admin.gallery\"]', 3, 'fa fa-image', 1);
INSERT INTO `admin_module` VALUES (20, 12, '友链', '/admin/blogroll/list', 'admin_blogroll_list', '[\"admin.blogroll\"]', 4, 'fa fa-link', 1);
COMMIT;

-- ----------------------------
-- Table structure for admin_user
-- ----------------------------
DROP TABLE IF EXISTS `admin_user`;
CREATE TABLE `admin_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户名',
  `avatar` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像',
  `email` varchar(180) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Email',
  `roles` json NOT NULL,
  `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `admin_user_group_id` int(11) DEFAULT '0' COMMENT '模块组ID',
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  `nickname` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '昵称',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `UNIQ_AD8A54A9E7927C74` (`email`) USING BTREE,
  UNIQUE KEY `UNIQ_AD8A54A9F85E0677` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统用户表';

-- ----------------------------
-- Records of admin_user
-- ----------------------------
BEGIN;
INSERT INTO `admin_user` VALUES (1, 'admin', '/uploads/admin_user/20201024/ab190d5d157d3dc23fce03b6784ed335.jpg', 'admin@info.com', '[\"ROLE_ADMIN\", \"ROLE_SONATA_ADMIN\"]', '$argon2id$v=19$m=65536,t=4,p=1$+wiK+JsHUyEoaMK9v967pQ$yPdNIEQl2HSpP6a9J3+jewvwdd8Amgg2oRq+jQ3YxY4', 1, '2020-03-21 01:01:20', '2020-10-24 21:46:35', '特立独行的ZHU');
INSERT INTO `admin_user` VALUES (5, 'user-long', '/uploads/admin_user/20200922/dc61f63fea5690104d4162d982dad026.jpg', 'beijing@info.com', '[\"ROLE_ADMIN\", \"ROLE_SONATA_ADMIN\"]', '$argon2id$v=19$m=65536,t=4,p=1$G0RuIV2bRLvvaYPzO8mFjg$kyre/Nz+/fiMDWHq6bmjZlva/pUSSfWRO9EtBPDfJhs', 2, '2020-04-02 13:50:21', '2020-09-23 10:28:52', '特立独行的LONG');
COMMIT;

-- ----------------------------
-- Table structure for admin_user_group
-- ----------------------------
DROP TABLE IF EXISTS `admin_user_group`;
CREATE TABLE `admin_user_group` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `module_ids` longtext COLLATE utf8mb4_unicode_ci,
  `is_super` tinyint(1) DEFAULT '0' COMMENT '是否超管 0否 1是',
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统用户组';

-- ----------------------------
-- Records of admin_user_group
-- ----------------------------
BEGIN;
INSERT INTO `admin_user_group` VALUES (1, '超级管理员', '[5,6,7,8,9,10,11,12,13,18,19,20,1,2,3,15,17,16]', 1, '2020-03-21 21:27:03', '2020-08-31 12:31:02');
INSERT INTO `admin_user_group` VALUES (2, '管理员', '[5,6,7,8,9,10,11,12,13,18,19,20]', 0, '2020-03-21 21:27:03', '2020-09-01 04:27:23');
COMMIT;

-- ----------------------------
-- Table structure for blogroll
-- ----------------------------
DROP TABLE IF EXISTS `blogroll`;
CREATE TABLE `blogroll` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `logo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `admin_user_id` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='友链表';

-- ----------------------------
-- Records of blogroll
-- ----------------------------
BEGIN;
INSERT INTO `blogroll` VALUES (3, '/uploads/blogroll/20200901/a7d7e7b6650faa0da2d2135e94e45e97.jpg', '风马博客', 'https://www.fengma.xin/', 1, '2020-09-01 19:02:53', NULL);
INSERT INTO `blogroll` VALUES (4, '/uploads/blogroll/20200901/f86e2ca5804f8b108ace1b5c8b3eea54.jpg', '低调小熊猫', 'http://ilovey.live/', 1, '2020-09-01 19:03:16', NULL);
COMMIT;

-- ----------------------------
-- Table structure for doctrine_migration_versions
-- ----------------------------
DROP TABLE IF EXISTS `doctrine_migration_versions`;
CREATE TABLE `doctrine_migration_versions` (
  `version` varchar(191) COLLATE utf8_unicode_ci NOT NULL,
  `executed_at` datetime DEFAULT NULL,
  `execution_time` int(11) DEFAULT NULL,
  PRIMARY KEY (`version`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='数据迁移表';

-- ----------------------------
-- Table structure for feedback
-- ----------------------------
DROP TABLE IF EXISTS `feedback`;
CREATE TABLE `feedback` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `nickname` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `content` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `ip` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `status` tinyint(1) DEFAULT '0' COMMENT '状态：0未读，1已读',
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='留言表';

-- ----------------------------
-- Records of feedback
-- ----------------------------
BEGIN;
INSERT INTO `feedback` VALUES (1, '嗷嗷嗷叫的小奶猫', '123123@info.com', '此处加锁的目的是为了在所有线程执行完后，切回到主线程中执行检查结果，如果调换的话，checkOnlyOne相当是加了一把互斥锁，不调换的话，相当于没有加锁。由于不涉及到多线程，只是单线程进行检查结果，所以无论调换与否都是没有问题的，我把它写到一起就是为了让人看清楚，那三行代码是为了挂起主线程，并不是为了加锁', '127.0.0.1', 0, '2020-08-18 22:29:32', '2020-09-22 06:28:28');
INSERT INTO `feedback` VALUES (2, '左侧心跳', '123123@info.com', '如果用户理特别大的情况下，上千万用户，即使概率很低也会出现的，况且iphone的硬件还远不如电脑，在iphone上的出现概率就会更高。这里只是给出一个小概率事件重现方法，只要是多线程使用单例就会出现上面的情况，只是几率的高低而已。上面是测试代码，这个你都看不懂吗，看来测试的目的你都不懂', '127.0.0.1', 0, '2020-08-19 22:29:32', '2020-09-22 06:28:29');
INSERT INTO `feedback` VALUES (3, '红色火龙果', '123123@info.com', '这和swift没关系吧，这是线程资源争用和执行原子性的问题，是编程方法的问题，和语言没有半点关系吧？难道是标题党？单例在判断是否为空时，应该同步的，否则肯定会出现问题，在多核CPU下出现的概率更明显。', '127.0.0.1', 1, '2020-08-19 22:29:32', '2020-09-22 06:29:27');
INSERT INTO `feedback` VALUES (4, '奔跑的蜗牛', '123123@info.com', '概率只是说说而已，这篇文章主要为初学单例出问题的一个重现方法，重点在测试不是在单例', '127.0.0.1', 0, '2020-08-19 22:29:32', '2020-09-22 06:28:31');
INSERT INTO `feedback` VALUES (5, '卖姑娘的小火柴 ', '23423@info.com', 'RPi还是不错的，我用的Raspbmc，2.5英寸的移动硬盘接在电脑上（PRi的USB口拖不动移动硬盘，需要使用有源的USB HUB，或者用带电源的3.5英寸盘），RPi通过SMB共享访问移动硬盘，播放720P(3到4个G)和1080P(10个G左右）的电影都完全没问题。不过有些家用无线路由的速度有可能会跟不上，插网线OK。', '127.0.0.1', 0, '2020-09-01 18:58:03', '2020-09-22 06:28:32');
INSERT INTO `feedback` VALUES (6, '孤独的根号三', 'genhaosan@info.com', '有时候觉得日子真奇怪，得到得不到都让人生难。', '127.0.0.1', 0, '2020-09-09 14:27:07', '2020-09-22 06:28:33');
INSERT INTO `feedback` VALUES (7, '不爱上班的琪琪格', 'qiqige@gaoblog.com', '很棒，奈斯，希望继续努力！！！', '127.0.0.1', 1, '2020-09-22 13:03:23', '2020-10-23 01:28:36');
COMMIT;

-- ----------------------------
-- Table structure for gallery
-- ----------------------------
DROP TABLE IF EXISTS `gallery`;
CREATE TABLE `gallery` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `original_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `size` int(11) DEFAULT NULL,
  `path` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `sort` int(11) DEFAULT NULL,
  `admin_user_id` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='图集表';

-- ----------------------------
-- Records of gallery
-- ----------------------------
BEGIN;
INSERT INTO `gallery` VALUES (30, '9a33bd6d24e37ec7c28807b63da38dce.jpg', 'img-11.jpg', 61645, '/uploads/gallery/20200831/9a33bd6d24e37ec7c28807b63da38dce.jpg', 5, 1, '2020-08-31 18:43:25', '2020-09-23 09:24:58');
INSERT INTO `gallery` VALUES (31, '9c9891addf994be245fa8b2dc9f06d31.jpg', 'img-12.jpg', 140837, '/uploads/gallery/20200831/9c9891addf994be245fa8b2dc9f06d31.jpg', 0, 1, '2020-08-31 18:43:25', '2020-09-23 09:24:58');
INSERT INTO `gallery` VALUES (32, '277c49e6e2b2f0e7af4ea6580e0a2032.jpg', 'img-13.jpg', 113464, '/uploads/gallery/20200831/277c49e6e2b2f0e7af4ea6580e0a2032.jpg', 1, 1, '2020-08-31 18:43:25', '2020-09-23 09:24:58');
INSERT INTO `gallery` VALUES (33, 'b276cf2da65ee51047936868cf3bb08a.jpg', 'img-14.jpg', 148615, '/uploads/gallery/20200831/b276cf2da65ee51047936868cf3bb08a.jpg', 2, 1, '2020-08-31 18:43:25', '2020-09-23 09:24:58');
INSERT INTO `gallery` VALUES (34, 'c35fe11f0da52b99e2692ceb0843923e.jpg', 'img-15.jpg', 39069, '/uploads/gallery/20200831/c35fe11f0da52b99e2692ceb0843923e.jpg', 3, 1, '2020-08-31 18:43:25', '2020-09-23 09:24:58');
INSERT INTO `gallery` VALUES (35, '193be313cc0bfd4c364f4b01b6188bec.jpg', '9b61c2e0ly1fufbe3a1doj20e60amgna.jpg', 72057, '/uploads/gallery/20200831/193be313cc0bfd4c364f4b01b6188bec.jpg', 4, 1, '2020-08-31 18:44:31', '2020-09-23 09:24:58');
INSERT INTO `gallery` VALUES (36, '0e276ffb4ba42d5847e100c5f4f17785.jpeg', '868b1041a4e6860414c740e52ad36610.jpeg', 90106, '/uploads/gallery/20200831/0e276ffb4ba42d5847e100c5f4f17785.jpeg', 7, 1, '2020-08-31 18:44:31', '2020-08-31 17:29:12');
INSERT INTO `gallery` VALUES (37, '38bdbf897ee596e56846fea9883db5f6.jpg', 'Cii9EVjqAMiIB22ZAAFtGbZzVMsAAJbcQOfYdEAAW0x98.jpg', 93465, '/uploads/gallery/20200831/38bdbf897ee596e56846fea9883db5f6.jpg', 6, 1, '2020-08-31 18:44:31', '2020-08-31 17:29:12');
INSERT INTO `gallery` VALUES (38, '7353d29f81e050c2d7dd4525dbcfd133.jpg', 'da0e1d3af7b47341b7784cb377831e83.jpg', 61791, '/uploads/gallery/20200831/7353d29f81e050c2d7dd4525dbcfd133.jpg', 8, 1, '2020-08-31 18:45:27', '2020-08-31 17:29:12');
INSERT INTO `gallery` VALUES (39, '849e74808f3260ea9a4f27e7daba867f.jpg', 'timg.jpg', 49404, '/uploads/gallery/20200831/849e74808f3260ea9a4f27e7daba867f.jpg', 9, 1, '2020-08-31 18:45:27', '2020-08-31 17:29:12');
COMMIT;

-- ----------------------------
-- Table structure for log
-- ----------------------------
DROP TABLE IF EXISTS `log`;
CREATE TABLE `log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `log_type_id` int(11) DEFAULT NULL,
  `description` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `parameter` longtext COLLATE utf8mb4_unicode_ci,
  `ip` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `admin_user_id` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='日志表';

-- ----------------------------
-- Records of log
-- ----------------------------
BEGIN;
INSERT INTO `log` VALUES (1, 29, '站点名称:[GaoBlog] 博主名称:[一个藤上三个瓜]', 'O:18:\"App\\Entity\\Setting\":25:{s:22:\"\0App\\Entity\\Setting\0id\";i:1;s:28:\"\0App\\Entity\\Setting\0seo_keys\";s:66:\"高,博客,开源,symfony,php,开源博客,php,php 博客,php blog\";s:35:\"\0App\\Entity\\Setting\0seo_description\";s:32:\"高的开源博客, symfony blog\";s:29:\"\0App\\Entity\\Setting\0site_name\";s:7:\"GaoBlog\";s:28:\"\0App\\Entity\\Setting\0site_url\";s:21:\"http://blog.gaoop.com\";s:29:\"\0App\\Entity\\Setting\0introduce\";s:162:\"星光不问赶路人，时光不负有心人。这个世界上真的有人在过着你想要的生活。而那些人大都曾隐忍过你尚未经历的挫折。\";s:24:\"\0App\\Entity\\Setting\0name\";s:21:\"一个藤上三个瓜\";s:26:\"\0App\\Entity\\Setting\0avatar\";s:62:\"/uploads/setting/20200906/70646e23c608808ecdde4719f7836614.jpg\";s:25:\"\0App\\Entity\\Setting\0image\";s:59:\"/uploads/page/20200908/25ade1fee0c9bef3c04ed9129cf8f8a8.jpg\";s:31:\"\0App\\Entity\\Setting\0description\";s:697:\"我们总以为阳光是来自于太阳，可是在我们心里幽暗的时候，再灿烂的阳光也不能把我们拉出阴影。其实，阳光不只是来自于太阳，也来自我们的心。只要我们心里有光，就会感应到世界的光彩；只要我们心里有光，就能与有缘有情的人相互照亮；只要我们心里有光，即便在最寒冷、阴霾的日子，也能感受到温暖！\r\n<br /><br />\r\n人总是在遭遇一次重创之后，才会幡然醒悟，重新认识自己的坚强和隐忍。所以，无论你正在遭遇什么磨难，都不要一味抱怨上苍不公平，甚至从此一蹶不振。人生没有过不去的坎，只有过不去的人。\";s:25:\"\0App\\Entity\\Setting\0phone\";s:11:\"17756573476\";s:25:\"\0App\\Entity\\Setting\0email\";s:17:\"gaoblog@gaoop.com\";s:27:\"\0App\\Entity\\Setting\0address\";s:56:\"安徽省合肥市蜀山区幸福小区2栋1单元302室\";s:29:\"\0App\\Entity\\Setting\0social_qq\";s:10:\"1241321748\";s:33:\"\0App\\Entity\\Setting\0social_wechat\";s:6:\"gaooop\";s:32:\"\0App\\Entity\\Setting\0social_weibo\";s:21:\"一个藤上三个瓜\";s:32:\"\0App\\Entity\\Setting\0social_qzone\";s:30:\"https://github.com/gaojinsheng\";s:34:\"\0App\\Entity\\Setting\0dashboard_type\";s:9:\"workbench\";s:32:\"\0App\\Entity\\Setting\0is_subscribe\";b:0;s:30:\"\0App\\Entity\\Setting\0is_comment\";b:1;s:40:\"\0App\\Entity\\Setting\0is_auto_pass_comment\";b:0;s:28:\"\0App\\Entity\\Setting\0is_reply\";b:0;s:34:\"\0App\\Entity\\Setting\0is_maintenance\";b:0;s:11:\"avatar_item\";a:0:{}s:10:\"image_item\";a:0:{}}', '127.0.0.1', 1, '2020-09-23 18:13:57');
INSERT INTO `log` VALUES (2, 30, '邮箱:[admin@info.com]', 'O:20:\"App\\Entity\\Subscribe\":6:{s:24:\"\0App\\Entity\\Subscribe\0id\";i:11;s:27:\"\0App\\Entity\\Subscribe\0email\";s:14:\"admin@info.com\";s:24:\"\0App\\Entity\\Subscribe\0ip\";s:9:\"127.0.0.1\";s:28:\"\0App\\Entity\\Subscribe\0status\";N;s:32:\"\0App\\Entity\\Subscribe\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-23 18:16:44.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:32:\"\0App\\Entity\\Subscribe\0updated_at\";N;}', '127.0.0.1', 1, '2020-09-23 18:17:18');
INSERT INTO `log` VALUES (3, 30, '邮箱:[user@info.com]', 'O:20:\"App\\Entity\\Subscribe\":6:{s:24:\"\0App\\Entity\\Subscribe\0id\";i:12;s:27:\"\0App\\Entity\\Subscribe\0email\";s:13:\"user@info.com\";s:24:\"\0App\\Entity\\Subscribe\0ip\";s:9:\"127.0.0.1\";s:28:\"\0App\\Entity\\Subscribe\0status\";N;s:32:\"\0App\\Entity\\Subscribe\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-23 18:16:50.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:32:\"\0App\\Entity\\Subscribe\0updated_at\";N;}', '127.0.0.1', 1, '2020-09-23 18:17:18');
INSERT INTO `log` VALUES (4, 5, '用户名:[hangzhou] - E-mail:[hangzhou@info.com] - 用户组:[管理员]', NULL, '127.0.0.1', 1, '2020-09-23 18:20:31');
INSERT INTO `log` VALUES (5, 4, '用户名:[user-long] - E-mail:[beijing@info.com] - 用户组:[管理员]', 'O:20:\"App\\Entity\\AdminUser\":11:{s:24:\"\0App\\Entity\\AdminUser\0id\";i:5;s:27:\"\0App\\Entity\\AdminUser\0email\";s:16:\"beijing@info.com\";s:30:\"\0App\\Entity\\AdminUser\0username\";s:9:\"user-long\";s:30:\"\0App\\Entity\\AdminUser\0nickname\";s:19:\"特立独行的LONG\";s:27:\"\0App\\Entity\\AdminUser\0roles\";a:2:{i:0;s:10:\"ROLE_ADMIN\";i:1;s:17:\"ROLE_SONATA_ADMIN\";}s:30:\"\0App\\Entity\\AdminUser\0password\";s:97:\"$argon2id$v=19$m=65536,t=4,p=1$G0RuIV2bRLvvaYPzO8mFjg$kyre/Nz+/fiMDWHq6bmjZlva/pUSSfWRO9EtBPDfJhs\";s:41:\"\0App\\Entity\\AdminUser\0admin_user_group_id\";i:2;s:32:\"\0App\\Entity\\AdminUser\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-04-02 13:50:21.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:32:\"\0App\\Entity\\AdminUser\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-22 09:46:59.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:28:\"\0App\\Entity\\AdminUser\0avatar\";s:65:\"/uploads/admin_user/20200922/dc61f63fea5690104d4162d982dad026.jpg\";s:11:\"avatar_item\";a:0:{}}', '127.0.0.1', 1, '2020-09-23 18:28:52');
INSERT INTO `log` VALUES (6, 1, '登录成功', NULL, '127.0.0.1', 5, '2020-09-23 18:29:07');
INSERT INTO `log` VALUES (7, 1, '登录成功', NULL, '127.0.0.1', 1, '2020-09-23 18:30:10');
INSERT INTO `log` VALUES (8, 21, '名称:[Symfony] 别名:[symfony]', 'O:15:\"App\\Entity\\Menu\":11:{s:19:\"\0App\\Entity\\Menu\0id\";i:3;s:22:\"\0App\\Entity\\Menu\0title\";s:7:\"Symfony\";s:28:\"\0App\\Entity\\Menu\0description\";s:95:\"Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community.\";s:20:\"\0App\\Entity\\Menu\0url\";N;s:33:\"\0App\\Entity\\Menu\0page_category_id\";i:2;s:22:\"\0App\\Entity\\Menu\0style\";s:4:\"list\";s:22:\"\0App\\Entity\\Menu\0alias\";s:7:\"symfony\";s:25:\"\0App\\Entity\\Menu\0position\";i:100;s:30:\"\0App\\Entity\\Menu\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Menu\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-08-20 22:39:07.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Menu\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-22 03:16:17.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}}', '127.0.0.1', 1, '2020-09-23 18:32:29');
INSERT INTO `log` VALUES (9, 29, '站点名称:[GaoBlog] 博主名称:[一个藤上三个瓜]', 'O:18:\"App\\Entity\\Setting\":25:{s:22:\"\0App\\Entity\\Setting\0id\";i:1;s:28:\"\0App\\Entity\\Setting\0seo_keys\";s:66:\"高,博客,开源,symfony,php,开源博客,php,php 博客,php blog\";s:35:\"\0App\\Entity\\Setting\0seo_description\";s:32:\"高的开源博客, symfony blog\";s:29:\"\0App\\Entity\\Setting\0site_name\";s:7:\"GaoBlog\";s:28:\"\0App\\Entity\\Setting\0site_url\";s:21:\"http://blog.gaoop.com\";s:29:\"\0App\\Entity\\Setting\0introduce\";s:162:\"星光不问赶路人，时光不负有心人。这个世界上真的有人在过着你想要的生活。而那些人大都曾隐忍过你尚未经历的挫折。\";s:24:\"\0App\\Entity\\Setting\0name\";s:21:\"一个藤上三个瓜\";s:26:\"\0App\\Entity\\Setting\0avatar\";s:62:\"/uploads/setting/20200906/70646e23c608808ecdde4719f7836614.jpg\";s:25:\"\0App\\Entity\\Setting\0image\";s:59:\"/uploads/page/20200908/25ade1fee0c9bef3c04ed9129cf8f8a8.jpg\";s:31:\"\0App\\Entity\\Setting\0description\";s:697:\"我们总以为阳光是来自于太阳，可是在我们心里幽暗的时候，再灿烂的阳光也不能把我们拉出阴影。其实，阳光不只是来自于太阳，也来自我们的心。只要我们心里有光，就会感应到世界的光彩；只要我们心里有光，就能与有缘有情的人相互照亮；只要我们心里有光，即便在最寒冷、阴霾的日子，也能感受到温暖！\r\n<br /><br />\r\n人总是在遭遇一次重创之后，才会幡然醒悟，重新认识自己的坚强和隐忍。所以，无论你正在遭遇什么磨难，都不要一味抱怨上苍不公平，甚至从此一蹶不振。人生没有过不去的坎，只有过不去的人。\";s:25:\"\0App\\Entity\\Setting\0phone\";s:11:\"17756573476\";s:25:\"\0App\\Entity\\Setting\0email\";s:17:\"gaoblog@gaoop.com\";s:27:\"\0App\\Entity\\Setting\0address\";s:56:\"安徽省合肥市蜀山区幸福小区2栋1单元302室\";s:29:\"\0App\\Entity\\Setting\0social_qq\";s:10:\"1241321748\";s:33:\"\0App\\Entity\\Setting\0social_wechat\";s:6:\"gaooop\";s:32:\"\0App\\Entity\\Setting\0social_weibo\";s:21:\"一个藤上三个瓜\";s:32:\"\0App\\Entity\\Setting\0social_qzone\";s:30:\"https://github.com/gaojinsheng\";s:34:\"\0App\\Entity\\Setting\0dashboard_type\";s:9:\"workbench\";s:32:\"\0App\\Entity\\Setting\0is_subscribe\";b:0;s:30:\"\0App\\Entity\\Setting\0is_comment\";b:1;s:40:\"\0App\\Entity\\Setting\0is_auto_pass_comment\";b:1;s:28:\"\0App\\Entity\\Setting\0is_reply\";b:1;s:34:\"\0App\\Entity\\Setting\0is_maintenance\";b:0;s:11:\"avatar_item\";a:0:{}s:10:\"image_item\";a:0:{}}', '127.0.0.1', 1, '2020-09-23 18:35:54');
INSERT INTO `log` VALUES (10, 29, '站点名称:[GaoBlog] 博主名称:[一个藤上三个瓜]', 'O:18:\"App\\Entity\\Setting\":25:{s:22:\"\0App\\Entity\\Setting\0id\";i:1;s:28:\"\0App\\Entity\\Setting\0seo_keys\";s:66:\"高,博客,开源,symfony,php,开源博客,php,php 博客,php blog\";s:35:\"\0App\\Entity\\Setting\0seo_description\";s:32:\"高的开源博客, symfony blog\";s:29:\"\0App\\Entity\\Setting\0site_name\";s:7:\"GaoBlog\";s:28:\"\0App\\Entity\\Setting\0site_url\";s:21:\"http://blog.gaoop.com\";s:29:\"\0App\\Entity\\Setting\0introduce\";s:162:\"星光不问赶路人，时光不负有心人。这个世界上真的有人在过着你想要的生活。而那些人大都曾隐忍过你尚未经历的挫折。\";s:24:\"\0App\\Entity\\Setting\0name\";s:21:\"一个藤上三个瓜\";s:26:\"\0App\\Entity\\Setting\0avatar\";s:62:\"/uploads/setting/20200906/70646e23c608808ecdde4719f7836614.jpg\";s:25:\"\0App\\Entity\\Setting\0image\";s:59:\"/uploads/page/20200908/25ade1fee0c9bef3c04ed9129cf8f8a8.jpg\";s:31:\"\0App\\Entity\\Setting\0description\";s:697:\"我们总以为阳光是来自于太阳，可是在我们心里幽暗的时候，再灿烂的阳光也不能把我们拉出阴影。其实，阳光不只是来自于太阳，也来自我们的心。只要我们心里有光，就会感应到世界的光彩；只要我们心里有光，就能与有缘有情的人相互照亮；只要我们心里有光，即便在最寒冷、阴霾的日子，也能感受到温暖！\r\n<br /><br />\r\n人总是在遭遇一次重创之后，才会幡然醒悟，重新认识自己的坚强和隐忍。所以，无论你正在遭遇什么磨难，都不要一味抱怨上苍不公平，甚至从此一蹶不振。人生没有过不去的坎，只有过不去的人。\";s:25:\"\0App\\Entity\\Setting\0phone\";s:11:\"17756573476\";s:25:\"\0App\\Entity\\Setting\0email\";s:17:\"gaoblog@gaoop.com\";s:27:\"\0App\\Entity\\Setting\0address\";s:56:\"安徽省合肥市蜀山区幸福小区2栋1单元302室\";s:29:\"\0App\\Entity\\Setting\0social_qq\";s:10:\"1241321748\";s:33:\"\0App\\Entity\\Setting\0social_wechat\";s:6:\"gaooop\";s:32:\"\0App\\Entity\\Setting\0social_weibo\";s:21:\"一个藤上三个瓜\";s:32:\"\0App\\Entity\\Setting\0social_qzone\";s:30:\"https://github.com/gaojinsheng\";s:34:\"\0App\\Entity\\Setting\0dashboard_type\";s:9:\"workbench\";s:32:\"\0App\\Entity\\Setting\0is_subscribe\";b:0;s:30:\"\0App\\Entity\\Setting\0is_comment\";b:1;s:40:\"\0App\\Entity\\Setting\0is_auto_pass_comment\";b:1;s:28:\"\0App\\Entity\\Setting\0is_reply\";b:0;s:34:\"\0App\\Entity\\Setting\0is_maintenance\";b:0;s:11:\"avatar_item\";a:0:{}s:10:\"image_item\";a:0:{}}', '127.0.0.1', 1, '2020-09-23 18:37:00');
INSERT INTO `log` VALUES (11, 29, '站点名称:[GaoBlog] 博主名称:[一个藤上三个瓜]', 'O:18:\"App\\Entity\\Setting\":25:{s:22:\"\0App\\Entity\\Setting\0id\";i:1;s:28:\"\0App\\Entity\\Setting\0seo_keys\";s:66:\"高,博客,开源,symfony,php,开源博客,php,php 博客,php blog\";s:35:\"\0App\\Entity\\Setting\0seo_description\";s:32:\"高的开源博客, symfony blog\";s:29:\"\0App\\Entity\\Setting\0site_name\";s:7:\"GaoBlog\";s:28:\"\0App\\Entity\\Setting\0site_url\";s:21:\"http://blog.gaoop.com\";s:29:\"\0App\\Entity\\Setting\0introduce\";s:162:\"星光不问赶路人，时光不负有心人。这个世界上真的有人在过着你想要的生活。而那些人大都曾隐忍过你尚未经历的挫折。\";s:24:\"\0App\\Entity\\Setting\0name\";s:21:\"一个藤上三个瓜\";s:26:\"\0App\\Entity\\Setting\0avatar\";s:62:\"/uploads/setting/20200906/70646e23c608808ecdde4719f7836614.jpg\";s:25:\"\0App\\Entity\\Setting\0image\";s:59:\"/uploads/page/20200908/25ade1fee0c9bef3c04ed9129cf8f8a8.jpg\";s:31:\"\0App\\Entity\\Setting\0description\";s:697:\"我们总以为阳光是来自于太阳，可是在我们心里幽暗的时候，再灿烂的阳光也不能把我们拉出阴影。其实，阳光不只是来自于太阳，也来自我们的心。只要我们心里有光，就会感应到世界的光彩；只要我们心里有光，就能与有缘有情的人相互照亮；只要我们心里有光，即便在最寒冷、阴霾的日子，也能感受到温暖！\r\n<br /><br />\r\n人总是在遭遇一次重创之后，才会幡然醒悟，重新认识自己的坚强和隐忍。所以，无论你正在遭遇什么磨难，都不要一味抱怨上苍不公平，甚至从此一蹶不振。人生没有过不去的坎，只有过不去的人。\";s:25:\"\0App\\Entity\\Setting\0phone\";s:11:\"17756573476\";s:25:\"\0App\\Entity\\Setting\0email\";s:17:\"gaoblog@gaoop.com\";s:27:\"\0App\\Entity\\Setting\0address\";s:56:\"安徽省合肥市蜀山区幸福小区2栋1单元302室\";s:29:\"\0App\\Entity\\Setting\0social_qq\";s:10:\"1241321748\";s:33:\"\0App\\Entity\\Setting\0social_wechat\";s:6:\"gaooop\";s:32:\"\0App\\Entity\\Setting\0social_weibo\";s:21:\"一个藤上三个瓜\";s:32:\"\0App\\Entity\\Setting\0social_qzone\";s:30:\"https://github.com/gaojinsheng\";s:34:\"\0App\\Entity\\Setting\0dashboard_type\";s:9:\"workbench\";s:32:\"\0App\\Entity\\Setting\0is_subscribe\";b:0;s:30:\"\0App\\Entity\\Setting\0is_comment\";b:1;s:40:\"\0App\\Entity\\Setting\0is_auto_pass_comment\";b:0;s:28:\"\0App\\Entity\\Setting\0is_reply\";b:0;s:34:\"\0App\\Entity\\Setting\0is_maintenance\";b:0;s:11:\"avatar_item\";a:0:{}s:10:\"image_item\";a:0:{}}', '127.0.0.1', 1, '2020-09-23 18:38:00');
INSERT INTO `log` VALUES (12, 30, '邮箱:[11@qq.com]', 'O:20:\"App\\Entity\\Subscribe\":6:{s:24:\"\0App\\Entity\\Subscribe\0id\";i:13;s:27:\"\0App\\Entity\\Subscribe\0email\";s:9:\"11@qq.com\";s:24:\"\0App\\Entity\\Subscribe\0ip\";s:9:\"127.0.0.1\";s:28:\"\0App\\Entity\\Subscribe\0status\";N;s:32:\"\0App\\Entity\\Subscribe\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-23 18:46:43.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:32:\"\0App\\Entity\\Subscribe\0updated_at\";N;}', '127.0.0.1', 1, '2020-09-23 18:47:20');
INSERT INTO `log` VALUES (13, 30, '邮箱:[131@qq.com]', 'O:20:\"App\\Entity\\Subscribe\":6:{s:24:\"\0App\\Entity\\Subscribe\0id\";i:14;s:27:\"\0App\\Entity\\Subscribe\0email\";s:10:\"131@qq.com\";s:24:\"\0App\\Entity\\Subscribe\0ip\";s:9:\"127.0.0.1\";s:28:\"\0App\\Entity\\Subscribe\0status\";N;s:32:\"\0App\\Entity\\Subscribe\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-23 18:46:47.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:32:\"\0App\\Entity\\Subscribe\0updated_at\";N;}', '127.0.0.1', 1, '2020-09-23 18:47:20');
INSERT INTO `log` VALUES (14, 16, '标题:[微软通过Windows搜索推送美国大选信息 全球用户都可以看到] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:31;s:22:\"\0App\\Entity\\Page\0title\";s:77:\"微软通过Windows搜索推送美国大选信息 全球用户都可以看到\";s:24:\"\0App\\Entity\\Page\0summary\";s:279:\"虽然其他国家的公民其实是不能投票决定未来4年谁将带领美国，但即将到来的美国大选对于全球而言都非常重要，因此，这并不妨碍微软通过Windows 10开始菜单的搜索结果页向全球Windows 10用户推送美国大选信息。\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200921/6b3c0ab71532bb5954d85c85241d3b76.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:3;s:26:\"\0App\\Entity\\Page\0page_tags\";a:3:{i:0;i:28;i:1;i:27;i:2;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:6:\"timing\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 19:06:21.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-23 09:53:42.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-22 01:20:39.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:30;s:26:\"\0App\\Entity\\Page\0page_like\";i:57;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-09-25 13:16:05');
INSERT INTO `log` VALUES (15, 16, '标题:[微软通过Windows搜索推送美国大选信息 全球用户都可以看到111] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:31;s:22:\"\0App\\Entity\\Page\0title\";s:80:\"微软通过Windows搜索推送美国大选信息 全球用户都可以看到111\";s:24:\"\0App\\Entity\\Page\0summary\";s:279:\"虽然其他国家的公民其实是不能投票决定未来4年谁将带领美国，但即将到来的美国大选对于全球而言都非常重要，因此，这并不妨碍微软通过Windows 10开始菜单的搜索结果页向全球Windows 10用户推送美国大选信息。\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200921/6b3c0ab71532bb5954d85c85241d3b76.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:3;s:26:\"\0App\\Entity\\Page\0page_tags\";a:3:{i:0;i:28;i:1;i:27;i:2;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:6:\"timing\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 19:06:21.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-23 09:53:42.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-22 01:20:39.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:30;s:26:\"\0App\\Entity\\Page\0page_like\";i:57;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-09-25 13:16:10');
INSERT INTO `log` VALUES (16, 16, '标题:[微软通过Windows搜索推送美国大选信息 全球用户都可以看到] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:31;s:22:\"\0App\\Entity\\Page\0title\";s:77:\"微软通过Windows搜索推送美国大选信息 全球用户都可以看到\";s:24:\"\0App\\Entity\\Page\0summary\";s:279:\"虽然其他国家的公民其实是不能投票决定未来4年谁将带领美国，但即将到来的美国大选对于全球而言都非常重要，因此，这并不妨碍微软通过Windows 10开始菜单的搜索结果页向全球Windows 10用户推送美国大选信息。\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200921/6b3c0ab71532bb5954d85c85241d3b76.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:3;s:26:\"\0App\\Entity\\Page\0page_tags\";a:3:{i:0;i:28;i:1;i:27;i:2;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:6:\"timing\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 19:06:21.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-25 05:16:10.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-22 01:20:39.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:30;s:26:\"\0App\\Entity\\Page\0page_like\";i:57;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-09-25 13:16:17');
INSERT INTO `log` VALUES (17, 16, '标题:[SymfonyLive Paris 2020: regular registration ends on March 2nd] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:15;s:22:\"\0App\\Entity\\Page\0title\";s:62:\"SymfonyLive Paris 2020: regular registration ends on March 2nd\";s:24:\"\0App\\Entity\\Page\0summary\";s:178:\"Only a few days left to register at the regular fee, price changes on March 2nd 2020. As the conference is organized in French, the following blog post will be written in French.\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200911/dfb914f17ed7454fbd7896e4bcd53e72.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:2;s:26:\"\0App\\Entity\\Page\0page_tags\";a:2:{i:0;i:1;i:1;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:3:\"now\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-11 18:06:22.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 16:54:18.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-25 13:16:27.188112\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:78;s:26:\"\0App\\Entity\\Page\0page_like\";i:46;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-09-25 13:16:27');
INSERT INTO `log` VALUES (18, 16, '标题:[微软通过Windows搜索推送美国大选信息 全球用户都可以看到] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:31;s:22:\"\0App\\Entity\\Page\0title\";s:77:\"微软通过Windows搜索推送美国大选信息 全球用户都可以看到\";s:24:\"\0App\\Entity\\Page\0summary\";s:279:\"虽然其他国家的公民其实是不能投票决定未来4年谁将带领美国，但即将到来的美国大选对于全球而言都非常重要，因此，这并不妨碍微软通过Windows 10开始菜单的搜索结果页向全球Windows 10用户推送美国大选信息。\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200921/6b3c0ab71532bb5954d85c85241d3b76.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:3;s:26:\"\0App\\Entity\\Page\0page_tags\";a:3:{i:0;i:28;i:1;i:27;i:2;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:6:\"timing\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 19:06:21.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-25 05:16:17.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-22 01:20:39.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:30;s:26:\"\0App\\Entity\\Page\0page_like\";i:57;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-09-28 05:37:58');
INSERT INTO `log` VALUES (19, 1, '登录成功', NULL, '127.0.0.1', 1, '2020-10-09 20:33:26');
INSERT INTO `log` VALUES (20, 4, '用户名:[admin] - E-mail:[admin@info.com] - 用户组:[超级管理员]', 'O:20:\"App\\Entity\\AdminUser\":11:{s:24:\"\0App\\Entity\\AdminUser\0id\";i:1;s:27:\"\0App\\Entity\\AdminUser\0email\";s:14:\"admin@info.com\";s:30:\"\0App\\Entity\\AdminUser\0username\";s:5:\"admin\";s:30:\"\0App\\Entity\\AdminUser\0nickname\";s:18:\"特立独行的ZHU\";s:27:\"\0App\\Entity\\AdminUser\0roles\";a:2:{i:0;s:10:\"ROLE_ADMIN\";i:1;s:17:\"ROLE_SONATA_ADMIN\";}s:30:\"\0App\\Entity\\AdminUser\0password\";s:97:\"$argon2id$v=19$m=65536,t=4,p=1$+wiK+JsHUyEoaMK9v967pQ$yPdNIEQl2HSpP6a9J3+jewvwdd8Amgg2oRq+jQ3YxY4\";s:41:\"\0App\\Entity\\AdminUser\0admin_user_group_id\";i:1;s:32:\"\0App\\Entity\\AdminUser\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-03-21 01:01:20.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:32:\"\0App\\Entity\\AdminUser\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-05 03:14:16.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:28:\"\0App\\Entity\\AdminUser\0avatar\";s:65:\"/uploads/admin_user/20200901/f46bed4f29c395997f0659b33b79da28.jpg\";s:11:\"avatar_item\";a:0:{}}', '127.0.0.1', 1, '2020-10-09 20:33:42');
INSERT INTO `log` VALUES (21, 10, '标签:[杂七杂八12]', 'O:18:\"App\\Entity\\PageTag\":5:{s:22:\"\0App\\Entity\\PageTag\0id\";i:28;s:25:\"\0App\\Entity\\PageTag\0value\";s:14:\"杂七杂八12\";s:33:\"\0App\\Entity\\PageTag\0admin_user_id\";i:1;s:30:\"\0App\\Entity\\PageTag\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 18:22:23.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:30:\"\0App\\Entity\\PageTag\0updated_at\";N;}', '127.0.0.1', 1, '2020-10-09 20:33:51');
INSERT INTO `log` VALUES (22, 10, '标签:[杂七杂八123]', 'O:18:\"App\\Entity\\PageTag\":5:{s:22:\"\0App\\Entity\\PageTag\0id\";i:28;s:25:\"\0App\\Entity\\PageTag\0value\";s:15:\"杂七杂八123\";s:33:\"\0App\\Entity\\PageTag\0admin_user_id\";i:1;s:30:\"\0App\\Entity\\PageTag\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 18:22:23.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:30:\"\0App\\Entity\\PageTag\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-09 12:33:51.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}}', '127.0.0.1', 1, '2020-10-09 20:33:53');
INSERT INTO `log` VALUES (23, 10, '标签:[杂七杂八]', 'O:18:\"App\\Entity\\PageTag\":5:{s:22:\"\0App\\Entity\\PageTag\0id\";i:28;s:25:\"\0App\\Entity\\PageTag\0value\";s:12:\"杂七杂八\";s:33:\"\0App\\Entity\\PageTag\0admin_user_id\";i:1;s:30:\"\0App\\Entity\\PageTag\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 18:22:23.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:30:\"\0App\\Entity\\PageTag\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-09 12:33:53.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}}', '127.0.0.1', 1, '2020-10-09 20:33:58');
INSERT INTO `log` VALUES (24, 16, '标题:[微软通过Windows搜索推送美国大选信息 全球用户都可以看到] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:31;s:22:\"\0App\\Entity\\Page\0title\";s:77:\"微软通过Windows搜索推送美国大选信息 全球用户都可以看到\";s:24:\"\0App\\Entity\\Page\0summary\";s:279:\"虽然其他国家的公民其实是不能投票决定未来4年谁将带领美国，但即将到来的美国大选对于全球而言都非常重要，因此，这并不妨碍微软通过Windows 10开始菜单的搜索结果页向全球Windows 10用户推送美国大选信息。\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200921/6b3c0ab71532bb5954d85c85241d3b76.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:3;s:26:\"\0App\\Entity\\Page\0page_tags\";a:3:{i:0;i:28;i:1;i:27;i:2;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:6:\"timing\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 19:06:21.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-25 05:16:17.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-22 01:20:39.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:30;s:26:\"\0App\\Entity\\Page\0page_like\";i:57;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-10-09 20:35:01');
INSERT INTO `log` VALUES (25, 1, '登录成功', NULL, '127.0.0.1', 1, '2020-10-09 23:17:04');
INSERT INTO `log` VALUES (26, 16, '标题:[SymfonyLive Paris 2020: regular registration ends on March 2nd] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:15;s:22:\"\0App\\Entity\\Page\0title\";s:62:\"SymfonyLive Paris 2020: regular registration ends on March 2nd\";s:24:\"\0App\\Entity\\Page\0summary\";s:178:\"Only a few days left to register at the regular fee, price changes on March 2nd 2020. As the conference is organized in French, the following blog post will be written in French.\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200911/dfb914f17ed7454fbd7896e4bcd53e72.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:2;s:26:\"\0App\\Entity\\Page\0page_tags\";a:2:{i:0;i:1;i:1;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:3:\"now\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-11 18:06:22.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-25 05:16:27.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-10 00:51:54.189314\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:78;s:26:\"\0App\\Entity\\Page\0page_like\";i:46;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-10-10 00:51:54');
INSERT INTO `log` VALUES (27, 10, '标签:[··23杂七杂八]', 'O:18:\"App\\Entity\\PageTag\":5:{s:22:\"\0App\\Entity\\PageTag\0id\";i:28;s:25:\"\0App\\Entity\\PageTag\0value\";s:18:\"··23杂七杂八\";s:33:\"\0App\\Entity\\PageTag\0admin_user_id\";i:1;s:30:\"\0App\\Entity\\PageTag\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 18:22:23.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:30:\"\0App\\Entity\\PageTag\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-09 12:33:58.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}}', '127.0.0.1', 1, '2020-10-10 00:52:03');
INSERT INTO `log` VALUES (28, 10, '标签:[杂七杂八]', 'O:18:\"App\\Entity\\PageTag\":5:{s:22:\"\0App\\Entity\\PageTag\0id\";i:28;s:25:\"\0App\\Entity\\PageTag\0value\";s:12:\"杂七杂八\";s:33:\"\0App\\Entity\\PageTag\0admin_user_id\";i:1;s:30:\"\0App\\Entity\\PageTag\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 18:22:23.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:30:\"\0App\\Entity\\PageTag\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-09 16:52:03.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}}', '127.0.0.1', 1, '2020-10-10 00:52:09');
INSERT INTO `log` VALUES (29, 10, '标签:[杂七杂八kjj]', 'O:18:\"App\\Entity\\PageTag\":5:{s:22:\"\0App\\Entity\\PageTag\0id\";i:28;s:25:\"\0App\\Entity\\PageTag\0value\";s:15:\"杂七杂八kjj\";s:33:\"\0App\\Entity\\PageTag\0admin_user_id\";i:1;s:30:\"\0App\\Entity\\PageTag\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 18:22:23.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:30:\"\0App\\Entity\\PageTag\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-09 16:52:09.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}}', '127.0.0.1', 1, '2020-10-10 01:07:45');
INSERT INTO `log` VALUES (30, 10, '标签:[杂七杂八]', 'O:18:\"App\\Entity\\PageTag\":5:{s:22:\"\0App\\Entity\\PageTag\0id\";i:28;s:25:\"\0App\\Entity\\PageTag\0value\";s:12:\"杂七杂八\";s:33:\"\0App\\Entity\\PageTag\0admin_user_id\";i:1;s:30:\"\0App\\Entity\\PageTag\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 18:22:23.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:30:\"\0App\\Entity\\PageTag\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-09 17:07:45.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}}', '127.0.0.1', 1, '2020-10-10 01:07:53');
INSERT INTO `log` VALUES (31, 1, '登录成功', NULL, '127.0.0.1', 1, '2020-10-11 23:44:04');
INSERT INTO `log` VALUES (32, 1, '登录成功', NULL, '127.0.0.1', 1, '2020-10-12 16:38:12');
INSERT INTO `log` VALUES (33, 16, '标题:[微软通过Windows搜索推送美国大选信息 全球用户都可以看到] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:31;s:22:\"\0App\\Entity\\Page\0title\";s:77:\"微软通过Windows搜索推送美国大选信息 全球用户都可以看到\";s:24:\"\0App\\Entity\\Page\0summary\";s:279:\"虽然其他国家的公民其实是不能投票决定未来4年谁将带领美国，但即将到来的美国大选对于全球而言都非常重要，因此，这并不妨碍微软通过Windows 10开始菜单的搜索结果页向全球Windows 10用户推送美国大选信息。\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200921/6b3c0ab71532bb5954d85c85241d3b76.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:3;s:26:\"\0App\\Entity\\Page\0page_tags\";a:3:{i:0;i:28;i:1;i:27;i:2;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:6:\"timing\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-21 19:06:21.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-09 12:35:01.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-22 01:20:39.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:30;s:26:\"\0App\\Entity\\Page\0page_like\";i:57;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-10-23 01:25:53');
INSERT INTO `log` VALUES (34, 16, '标题:[SymfonyLive Paris 2020: regular registration ends on March 2nd] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:15;s:22:\"\0App\\Entity\\Page\0title\";s:62:\"SymfonyLive Paris 2020: regular registration ends on March 2nd\";s:24:\"\0App\\Entity\\Page\0summary\";s:178:\"Only a few days left to register at the regular fee, price changes on March 2nd 2020. As the conference is organized in French, the following blog post will be written in French.\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200911/dfb914f17ed7454fbd7896e4bcd53e72.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:2;s:26:\"\0App\\Entity\\Page\0page_tags\";a:2:{i:0;i:1;i:1;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:3:\"now\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-11 18:06:22.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-09 16:51:54.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-23 21:09:38.755826\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:78;s:26:\"\0App\\Entity\\Page\0page_like\";i:46;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-10-23 21:09:38');
INSERT INTO `log` VALUES (35, 16, '标题:[SymfonyLive Paris 2020: regular registration ends on March 2nd] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:15;s:22:\"\0App\\Entity\\Page\0title\";s:62:\"SymfonyLive Paris 2020: regular registration ends on March 2nd\";s:24:\"\0App\\Entity\\Page\0summary\";s:178:\"Only a few days left to register at the regular fee, price changes on March 2nd 2020. As the conference is organized in French, the following blog post will be written in French.\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200911/dfb914f17ed7454fbd7896e4bcd53e72.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:2;s:26:\"\0App\\Entity\\Page\0page_tags\";a:2:{i:0;i:1;i:1;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:3:\"now\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-11 18:06:22.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-23 21:09:38.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-24 21:45:25.467886\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:78;s:26:\"\0App\\Entity\\Page\0page_like\";i:46;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-10-24 21:45:25');
INSERT INTO `log` VALUES (36, 4, '用户名:[admin] - E-mail:[admin@info.com] - 用户组:[超级管理员]', 'O:20:\"App\\Entity\\AdminUser\":11:{s:24:\"\0App\\Entity\\AdminUser\0id\";i:1;s:27:\"\0App\\Entity\\AdminUser\0email\";s:14:\"admin@info.com\";s:30:\"\0App\\Entity\\AdminUser\0username\";s:5:\"admin\";s:30:\"\0App\\Entity\\AdminUser\0nickname\";s:18:\"特立独行的ZHU\";s:27:\"\0App\\Entity\\AdminUser\0roles\";a:2:{i:0;s:10:\"ROLE_ADMIN\";i:1;s:17:\"ROLE_SONATA_ADMIN\";}s:30:\"\0App\\Entity\\AdminUser\0password\";s:97:\"$argon2id$v=19$m=65536,t=4,p=1$+wiK+JsHUyEoaMK9v967pQ$yPdNIEQl2HSpP6a9J3+jewvwdd8Amgg2oRq+jQ3YxY4\";s:41:\"\0App\\Entity\\AdminUser\0admin_user_group_id\";i:1;s:32:\"\0App\\Entity\\AdminUser\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-03-21 01:01:20.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:32:\"\0App\\Entity\\AdminUser\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-05 03:14:16.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:28:\"\0App\\Entity\\AdminUser\0avatar\";s:65:\"/uploads/admin_user/20201024/3edaf096c67d428a7b583fe36d05c993.jpg\";s:11:\"avatar_item\";a:0:{}}', '127.0.0.1', 1, '2020-10-24 21:46:20');
INSERT INTO `log` VALUES (37, 4, '用户名:[admin] - E-mail:[admin@info.com] - 用户组:[超级管理员]', 'O:20:\"App\\Entity\\AdminUser\":11:{s:24:\"\0App\\Entity\\AdminUser\0id\";i:1;s:27:\"\0App\\Entity\\AdminUser\0email\";s:14:\"admin@info.com\";s:30:\"\0App\\Entity\\AdminUser\0username\";s:5:\"admin\";s:30:\"\0App\\Entity\\AdminUser\0nickname\";s:18:\"特立独行的ZHU\";s:27:\"\0App\\Entity\\AdminUser\0roles\";a:2:{i:0;s:10:\"ROLE_ADMIN\";i:1;s:17:\"ROLE_SONATA_ADMIN\";}s:30:\"\0App\\Entity\\AdminUser\0password\";s:97:\"$argon2id$v=19$m=65536,t=4,p=1$+wiK+JsHUyEoaMK9v967pQ$yPdNIEQl2HSpP6a9J3+jewvwdd8Amgg2oRq+jQ3YxY4\";s:41:\"\0App\\Entity\\AdminUser\0admin_user_group_id\";i:1;s:32:\"\0App\\Entity\\AdminUser\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-03-21 01:01:20.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:32:\"\0App\\Entity\\AdminUser\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-24 21:46:20.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:28:\"\0App\\Entity\\AdminUser\0avatar\";s:65:\"/uploads/admin_user/20201024/ab190d5d157d3dc23fce03b6784ed335.jpg\";s:11:\"avatar_item\";a:0:{}}', '127.0.0.1', 1, '2020-10-24 21:46:35');
INSERT INTO `log` VALUES (38, 16, '标题:[SymfonyLive Paris 2020: regular registration ends on March 2nd] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:15;s:22:\"\0App\\Entity\\Page\0title\";s:62:\"SymfonyLive Paris 2020: regular registration ends on March 2nd\";s:24:\"\0App\\Entity\\Page\0summary\";s:178:\"Only a few days left to register at the regular fee, price changes on March 2nd 2020. As the conference is organized in French, the following blog post will be written in French.\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200911/dfb914f17ed7454fbd7896e4bcd53e72.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:2;s:26:\"\0App\\Entity\\Page\0page_tags\";a:2:{i:0;i:1;i:1;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:3:\"now\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-11 18:06:22.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-24 21:48:31.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-25 23:25:11.669299\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:79;s:26:\"\0App\\Entity\\Page\0page_like\";i:46;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-10-25 23:25:11');
INSERT INTO `log` VALUES (39, 1, '登录成功', NULL, '127.0.0.1', 1, '2020-10-25 23:55:28');
INSERT INTO `log` VALUES (40, 29, '站点名称:[GaoBlog] 博主名称:[一个藤上三个瓜]', 'O:18:\"App\\Entity\\Setting\":25:{s:22:\"\0App\\Entity\\Setting\0id\";i:1;s:28:\"\0App\\Entity\\Setting\0seo_keys\";s:66:\"高,博客,开源,symfony,php,开源博客,php,php 博客,php blog\";s:35:\"\0App\\Entity\\Setting\0seo_description\";s:32:\"高的开源博客, symfony blog\";s:29:\"\0App\\Entity\\Setting\0site_name\";s:7:\"GaoBlog\";s:28:\"\0App\\Entity\\Setting\0site_url\";s:21:\"http://blog.gaoop.com\";s:29:\"\0App\\Entity\\Setting\0introduce\";s:162:\"星光不问赶路人，时光不负有心人。这个世界上真的有人在过着你想要的生活。而那些人大都曾隐忍过你尚未经历的挫折。\";s:24:\"\0App\\Entity\\Setting\0name\";s:21:\"一个藤上三个瓜\";s:26:\"\0App\\Entity\\Setting\0avatar\";s:62:\"/uploads/setting/20200906/70646e23c608808ecdde4719f7836614.jpg\";s:25:\"\0App\\Entity\\Setting\0image\";s:59:\"/uploads/page/20200908/25ade1fee0c9bef3c04ed9129cf8f8a8.jpg\";s:31:\"\0App\\Entity\\Setting\0description\";s:697:\"我们总以为阳光是来自于太阳，可是在我们心里幽暗的时候，再灿烂的阳光也不能把我们拉出阴影。其实，阳光不只是来自于太阳，也来自我们的心。只要我们心里有光，就会感应到世界的光彩；只要我们心里有光，就能与有缘有情的人相互照亮；只要我们心里有光，即便在最寒冷、阴霾的日子，也能感受到温暖！\r\n<br /><br />\r\n人总是在遭遇一次重创之后，才会幡然醒悟，重新认识自己的坚强和隐忍。所以，无论你正在遭遇什么磨难，都不要一味抱怨上苍不公平，甚至从此一蹶不振。人生没有过不去的坎，只有过不去的人。\";s:25:\"\0App\\Entity\\Setting\0phone\";s:11:\"17756573476\";s:25:\"\0App\\Entity\\Setting\0email\";s:17:\"gaoblog@gaoop.com\";s:27:\"\0App\\Entity\\Setting\0address\";s:56:\"安徽省合肥市蜀山区幸福小区2栋1单元302室\";s:29:\"\0App\\Entity\\Setting\0social_qq\";s:10:\"1241321748\";s:33:\"\0App\\Entity\\Setting\0social_wechat\";s:6:\"gaooop\";s:32:\"\0App\\Entity\\Setting\0social_weibo\";s:21:\"一个藤上三个瓜\";s:32:\"\0App\\Entity\\Setting\0social_qzone\";s:30:\"https://github.com/gaojinsheng\";s:34:\"\0App\\Entity\\Setting\0dashboard_type\";s:8:\"classics\";s:32:\"\0App\\Entity\\Setting\0is_subscribe\";b:0;s:30:\"\0App\\Entity\\Setting\0is_comment\";b:1;s:40:\"\0App\\Entity\\Setting\0is_auto_pass_comment\";b:0;s:28:\"\0App\\Entity\\Setting\0is_reply\";b:0;s:34:\"\0App\\Entity\\Setting\0is_maintenance\";b:0;s:11:\"avatar_item\";a:0:{}s:10:\"image_item\";a:0:{}}', '::1', 1, '2020-10-28 19:55:01');
INSERT INTO `log` VALUES (41, 29, '站点名称:[GaoBlog] 博主名称:[一个藤上三个瓜]', 'O:18:\"App\\Entity\\Setting\":25:{s:22:\"\0App\\Entity\\Setting\0id\";i:1;s:28:\"\0App\\Entity\\Setting\0seo_keys\";s:66:\"高,博客,开源,symfony,php,开源博客,php,php 博客,php blog\";s:35:\"\0App\\Entity\\Setting\0seo_description\";s:32:\"高的开源博客, symfony blog\";s:29:\"\0App\\Entity\\Setting\0site_name\";s:7:\"GaoBlog\";s:28:\"\0App\\Entity\\Setting\0site_url\";s:21:\"http://blog.gaoop.com\";s:29:\"\0App\\Entity\\Setting\0introduce\";s:162:\"星光不问赶路人，时光不负有心人。这个世界上真的有人在过着你想要的生活。而那些人大都曾隐忍过你尚未经历的挫折。\";s:24:\"\0App\\Entity\\Setting\0name\";s:21:\"一个藤上三个瓜\";s:26:\"\0App\\Entity\\Setting\0avatar\";s:62:\"/uploads/setting/20200906/70646e23c608808ecdde4719f7836614.jpg\";s:25:\"\0App\\Entity\\Setting\0image\";s:59:\"/uploads/page/20200908/25ade1fee0c9bef3c04ed9129cf8f8a8.jpg\";s:31:\"\0App\\Entity\\Setting\0description\";s:697:\"我们总以为阳光是来自于太阳，可是在我们心里幽暗的时候，再灿烂的阳光也不能把我们拉出阴影。其实，阳光不只是来自于太阳，也来自我们的心。只要我们心里有光，就会感应到世界的光彩；只要我们心里有光，就能与有缘有情的人相互照亮；只要我们心里有光，即便在最寒冷、阴霾的日子，也能感受到温暖！\r\n<br /><br />\r\n人总是在遭遇一次重创之后，才会幡然醒悟，重新认识自己的坚强和隐忍。所以，无论你正在遭遇什么磨难，都不要一味抱怨上苍不公平，甚至从此一蹶不振。人生没有过不去的坎，只有过不去的人。\";s:25:\"\0App\\Entity\\Setting\0phone\";s:11:\"17756573476\";s:25:\"\0App\\Entity\\Setting\0email\";s:17:\"gaoblog@gaoop.com\";s:27:\"\0App\\Entity\\Setting\0address\";s:56:\"安徽省合肥市蜀山区幸福小区2栋1单元302室\";s:29:\"\0App\\Entity\\Setting\0social_qq\";s:10:\"1241321748\";s:33:\"\0App\\Entity\\Setting\0social_wechat\";s:6:\"gaooop\";s:32:\"\0App\\Entity\\Setting\0social_weibo\";s:21:\"一个藤上三个瓜\";s:32:\"\0App\\Entity\\Setting\0social_qzone\";s:30:\"https://github.com/gaojinsheng\";s:34:\"\0App\\Entity\\Setting\0dashboard_type\";s:9:\"workbench\";s:32:\"\0App\\Entity\\Setting\0is_subscribe\";b:0;s:30:\"\0App\\Entity\\Setting\0is_comment\";b:1;s:40:\"\0App\\Entity\\Setting\0is_auto_pass_comment\";b:0;s:28:\"\0App\\Entity\\Setting\0is_reply\";b:0;s:34:\"\0App\\Entity\\Setting\0is_maintenance\";b:0;s:11:\"avatar_item\";a:0:{}s:10:\"image_item\";a:0:{}}', '::1', 1, '2020-10-28 19:55:15');
INSERT INTO `log` VALUES (42, 16, '标题:[SymfonyLive Paris 2020: regular registration ends on March 2nd] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:15;s:22:\"\0App\\Entity\\Page\0title\";s:62:\"SymfonyLive Paris 2020: regular registration ends on March 2nd\";s:24:\"\0App\\Entity\\Page\0summary\";s:178:\"Only a few days left to register at the regular fee, price changes on March 2nd 2020. As the conference is organized in French, the following blog post will be written in French.\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200911/dfb914f17ed7454fbd7896e4bcd53e72.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:2;s:26:\"\0App\\Entity\\Page\0page_tags\";a:2:{i:0;i:1;i:1;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:3:\"now\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-11 18:06:22.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-25 23:25:11.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-29 00:00:17.257835\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:79;s:26:\"\0App\\Entity\\Page\0page_like\";i:46;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-10-29 00:00:17');
INSERT INTO `log` VALUES (43, 16, '标题:[SymfonyLive Paris 2020: regular registration ends on March 2nd] ', 'O:15:\"App\\Entity\\Page\":24:{s:19:\"\0App\\Entity\\Page\0id\";i:15;s:22:\"\0App\\Entity\\Page\0title\";s:62:\"SymfonyLive Paris 2020: regular registration ends on March 2nd\";s:24:\"\0App\\Entity\\Page\0summary\";s:178:\"Only a few days left to register at the regular fee, price changes on March 2nd 2020. As the conference is organized in French, the following blog post will be written in French.\";s:24:\"\0App\\Entity\\Page\0content\";s:0:\"\";s:26:\"\0App\\Entity\\Page\0thumbnail\";s:59:\"/uploads/page/20200911/dfb914f17ed7454fbd7896e4bcd53e72.jpg\";s:27:\"\0App\\Entity\\Page\0is_comment\";b:1;s:33:\"\0App\\Entity\\Page\0page_category_id\";i:2;s:26:\"\0App\\Entity\\Page\0page_tags\";a:2:{i:0;i:1;i:1;i:2;}s:23:\"\0App\\Entity\\Page\0status\";i:1;s:29:\"\0App\\Entity\\Page\0publish_type\";s:3:\"now\";s:30:\"\0App\\Entity\\Page\0admin_user_id\";i:1;s:27:\"\0App\\Entity\\Page\0created_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-09-11 18:06:22.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:27:\"\0App\\Entity\\Page\0updated_at\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-10-29 00:00:17.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:29:\"\0App\\Entity\\Page\0publish_time\";O:8:\"DateTime\":3:{s:4:\"date\";s:26:\"2020-11-01 08:52:25.317927\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:3:\"PRC\";}s:26:\"\0App\\Entity\\Page\0page_view\";i:79;s:26:\"\0App\\Entity\\Page\0page_like\";i:46;s:23:\"\0App\\Entity\\Page\0is_top\";b:0;s:29:\"\0App\\Entity\\Page\0is_recommend\";b:0;s:31:\"\0App\\Entity\\Page\0publish_status\";b:1;s:24:\"\0App\\Entity\\Page\0seo_key\";N;s:32:\"\0App\\Entity\\Page\0seo_description\";N;s:12:\"page_publish\";a:0:{}s:14:\"thumbnail_item\";a:0:{}s:6:\"author\";N;}', '127.0.0.1', 1, '2020-11-01 08:52:25');
COMMIT;

-- ----------------------------
-- Table structure for log_type
-- ----------------------------
DROP TABLE IF EXISTS `log_type`;
CREATE TABLE `log_type` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `value` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='日志类型表';

-- ----------------------------
-- Records of log_type
-- ----------------------------
BEGIN;
INSERT INTO `log_type` VALUES (1, '登录-成功');
INSERT INTO `log_type` VALUES (2, '登录-失败');
INSERT INTO `log_type` VALUES (3, '用户-创建');
INSERT INTO `log_type` VALUES (4, '用户-修改');
INSERT INTO `log_type` VALUES (5, '用户-删除');
INSERT INTO `log_type` VALUES (6, '用户组-创建');
INSERT INTO `log_type` VALUES (7, '用户组-修改');
INSERT INTO `log_type` VALUES (8, '用户组-删除');
INSERT INTO `log_type` VALUES (9, '标签-创建');
INSERT INTO `log_type` VALUES (10, '标签-修改');
INSERT INTO `log_type` VALUES (11, '标签-删除');
INSERT INTO `log_type` VALUES (12, '类别-创建');
INSERT INTO `log_type` VALUES (13, '类别-修改');
INSERT INTO `log_type` VALUES (14, '类别-删除');
INSERT INTO `log_type` VALUES (15, '文章-创建');
INSERT INTO `log_type` VALUES (16, '文章-修改');
INSERT INTO `log_type` VALUES (17, '文章-删除');
INSERT INTO `log_type` VALUES (18, '评论-删除');
INSERT INTO `log_type` VALUES (19, '留言-删除');
INSERT INTO `log_type` VALUES (20, '菜单-新建');
INSERT INTO `log_type` VALUES (21, '菜单-修改');
INSERT INTO `log_type` VALUES (22, '菜单-删除');
INSERT INTO `log_type` VALUES (23, '图集-新建');
INSERT INTO `log_type` VALUES (24, '图集-修改');
INSERT INTO `log_type` VALUES (25, '图集-删除');
INSERT INTO `log_type` VALUES (26, '友链-新建');
INSERT INTO `log_type` VALUES (27, '友链-修改');
INSERT INTO `log_type` VALUES (28, '友链-删除');
INSERT INTO `log_type` VALUES (29, '设置-修改');
INSERT INTO `log_type` VALUES (30, '订阅-删除');
COMMIT;

-- ----------------------------
-- Table structure for menu
-- ----------------------------
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `alias` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `page_category_id` int(11) DEFAULT NULL,
  `style` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `position` int(11) DEFAULT '1',
  `admin_user_id` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  `description` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='菜单表';

-- ----------------------------
-- Records of menu
-- ----------------------------
BEGIN;
INSERT INTO `menu` VALUES (3, 'Symfony', 'symfony', NULL, 2, 'list', 100, 1, '2020-08-20 22:39:07', '2020-09-23 10:32:29', 'Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community.');
INSERT INTO `menu` VALUES (4, '技术杂文', 'other', NULL, 1, 'list', 11, 1, '2020-08-20 22:40:59', '2020-09-07 11:53:38', '竖子欺吾年老！吾手中宝刀却不老。');
INSERT INTO `menu` VALUES (5, '生活随笔', 'life', NULL, 3, 'image', 23, 1, '2020-08-20 22:41:15', '2020-09-07 11:54:13', '星光不问赶路人，时光不负有心人。');
INSERT INTO `menu` VALUES (9, 'Sonata-project', 'sonata', 'https://sonata-project.org/', NULL, NULL, 13, 1, '2020-08-20 23:11:28', '2020-09-07 11:13:31', NULL);
COMMIT;

-- ----------------------------
-- Table structure for messenger_messages
-- ----------------------------
DROP TABLE IF EXISTS `messenger_messages`;
CREATE TABLE `messenger_messages` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `body` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `headers` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `queue_name` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
  `created_at` datetime NOT NULL,
  `available_at` datetime NOT NULL,
  `delivered_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_75EA56E0FB7336F0` (`queue_name`),
  KEY `IDX_75EA56E0E3BD61CE` (`available_at`),
  KEY `IDX_75EA56E016BA31DB` (`delivered_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ----------------------------
-- Table structure for migration_versions
-- ----------------------------
DROP TABLE IF EXISTS `migration_versions`;
CREATE TABLE `migration_versions` (
  `version` varchar(14) COLLATE utf8mb4_unicode_ci NOT NULL,
  `executed_at` datetime NOT NULL COMMENT '(DC2Type:datetime_immutable)',
  PRIMARY KEY (`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ----------------------------
-- Table structure for page
-- ----------------------------
DROP TABLE IF EXISTS `page`;
CREATE TABLE `page` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `page_category_id` int(11) NOT NULL COMMENT '类别ID',
  `title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '标题',
  `summary` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '摘要',
  `content` longtext COLLATE utf8mb4_unicode_ci COMMENT '正文内容',
  `thumbnail` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缩率图',
  `is_comment` tinyint(1) DEFAULT '0' COMMENT '是否开启评论，0关闭，1开启',
  `page_tags` json DEFAULT NULL COMMENT '标签',
  `page_view` int(11) DEFAULT '0' COMMENT '阅读量',
  `publish_time` datetime DEFAULT NULL COMMENT '发布时间',
  `publish_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT 'now' COMMENT '发布模式：now及时发布，timing定时发布',
  `publish_status` tinyint(1) DEFAULT '1' COMMENT '发布状态：0待发布，1已发布',
  `page_like` int(11) DEFAULT '0' COMMENT '点赞量',
  `is_recommend` tinyint(1) DEFAULT '0' COMMENT '推荐：0否，1是',
  `is_top` tinyint(1) DEFAULT '0' COMMENT '置顶：0否，1是',
  `seo_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'seo 关键词',
  `seo_description` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'seo 描述',
  `status` int(11) DEFAULT '1' COMMENT '状态：-1删除，0待发布，1已发布',
  `admin_user_id` int(11) DEFAULT NULL COMMENT '创建人ID',
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='文章表';

-- ----------------------------
-- Records of page
-- ----------------------------
BEGIN;
INSERT INTO `page` VALUES (1, 3, 'Mysql的优化策略，提升PHP的运行效率', '为了提升PHP的运行效率，程序员不光需要写出逻辑清晰，效率很高的代码，还要能对query语句进行优化。虽然我们对数据库的读取写入速度上却是无能为力，但在一些数据库类扩展像memcache、mongodb、redis这样的数据存储服务器的帮助下，PHP也能达到更快的存取速度，所以了解学习这些扩展也是非常必要。', '<p>为了提升PHP的运行效率，程序员不光需要写出逻辑清晰，效率很高的代码，还要能对query语句进行优化。虽然我们对数据库的读取写入速度上却是无能为力，但在一些数据库类扩展像memcache、mongodb、redis这样的数据存储服务器的帮助下，PHP也能达到更快的存取速度，所以了解学习这些扩展也是非常必要。</p><p><strong>大型存储方面优化</strong></p><p><strong>数据库主从复制和读写分离</strong></p><p>1、master将改变记录到二进制日志中，slave将master的二进制拷贝到它的中继日志中，重新将数据返回到它自己的数据中，达到复制主服务器数据的目的。 主从复制可以用作：数据库负载均衡、数据库备份、读写分离等功能。 2、配置主服务器master 　　修改my.ini/my.conf 　　[mysqld] 　　log-bin=mysql-bin //启用二进制日志 　　server-id=102 //服务器唯一ID 3、配置从服务器slave 　　log-bin=mysql-bin //启用二进制日志 　　server-id=226 //服务器唯一ID 4、在主服务器上授权从服务器 GRANT REPLICATION SLAVE ON *.* to \'slavename\'@\'IP\' identified by \'root\' 5、在从服务器上使用 　　change master to 　　master_host=\"masterip\", 　　master_user=\"masteruser\", 　　master_password=\"masterpasswd\"; 6、然后使用start slave命令开始进行主从复制。 不要忘记在每次修改配置后重启服务器，然后可以在主从服务器上用show master/slave status查看主/从状态。 实现数据库的读写分离要依赖MySQL的中间件，如mysql_proxy，atlas等。通过配置这些中间件来对主从服务器进行读写分离，使从服务器承担被读取的责任，从而减轻主服务器的负担。</p><p>&nbsp;</p><p><strong>数据库的sharding</strong><br>在数据库中数据表中的数据量非常庞大的时候，无论是索引还是缓存等压力都很大，对数据库进行sharding，使之分别以多个数据库服务器或多个表存储，以减轻查询压力。方式有垂直切分、水平切分和联合切分。</p><p><br>垂直切分：在数据表非常多的时候，把数据库中关系紧密(如同一模块，经常连接查询)的表切分出来分别放到不同的主从server上。</p><p><br>水平切分：在表不多，而表里的数据量非常大的时候，为了加快查询，可以用哈希等算法，将一个数据表分为几个，分别放到不同的服务器上，加快查询。水平切分和数据表分区的区别在于其存储介质上的不同。</p><p><br>联合切分：更多的情况是数据表和表中的数据量都非常大，则要进行联合切分，即同时进行垂直和水平分表，将数据库切分为一个分布式的矩阵来存储。<br>这些数据库的优化方式，每一种拿出来都可以写作一篇文章，可谓是博大精深，了解并记忆了这些方式，可以在有需要的时候进行有目的的选择优化，达到数据库效率的高效。</p><p>&nbsp;</p><p><strong>索引方面优化</strong></p><p>在MySQL中，索引属于存储引擎级别的概念，不同存储引擎对索引的实现方式是不同的，下面主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式。</p><h2><strong>MyISAM索引实现</strong></h2><p>MyISAM引擎使用B+Tree作为索引结构，叶节点的data域存放的是数据记录的地址。下图是MyISAM索引的原理图：</p><figure class=\"image\"><img src=\"https://pic3.zhimg.com/80/v2-42a585811f71901dda11477d4d49bacf_720w.jpg\"></figure><p>这里设表一共有三列，假设我们以Col1为主键，则图1是一个MyISAM表的主索引（Primary key）示意。可以看出MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中，主索引和辅助索引（Secondary key）在结构上没有任何区别，只是主索引要求key是唯一的，而辅助索引的key可以重复。如果我们在Col2上建立一个辅助索引，则此索引的结构如下图所示：</p><figure class=\"image\"><img src=\"https://pic4.zhimg.com/80/v2-dbd232a47f1117f0a340635b6dc977d2_720w.jpg\"></figure><p>同样也是一颗B+Tree，data域保存数据记录的地址。因此，MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引，如果指定的Key存在，则取出其data域的值，然后以data域的值为地址，读取相应数据记录。</p><p>MyISAM的索引方式也叫做“非聚集”的，之所以这么称呼是为了与InnoDB的聚集索引区分。</p><h2><strong>InnoDB索引实现</strong></h2><p>虽然InnoDB也使用B+Tree作为索引结构，但具体实现方式却与MyISAM截然不同。</p><p>第一个重大区别是InnoDB的数据文件本身就是索引文件。从上文知道，MyISAM索引文件和数据文件是分离的，索引文件仅保存数据记录的地址。而在InnoDB中，表数据文件本身就是按B+Tree组织的一个索引结构，这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键，因此InnoDB表数据文件本身就是主索引。</p><figure class=\"image\"><img src=\"https://pic3.zhimg.com/80/v2-d6f72fbcccdb359af3265e59705a639e_720w.jpg\"></figure><p>图3</p><p>图3是InnoDB主索引（同时也是数据文件）的示意图，可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚集，所以InnoDB要求表必须有主键（MyISAM可以没有），如果没有显式指定，则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键，如果不存在这种列，则MySQL自动为InnoDB表生成一个隐含字段作为主键，这个字段长度为6个字节，类型为长整形。</p><p>&nbsp;</p><p>第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说，InnoDB的所有辅助索引都引用主键作为data域。例如，图4为定义在Col3上的一个辅助索引：</p><figure class=\"image\"><img src=\"https://pic3.zhimg.com/80/v2-d6f72fbcccdb359af3265e59705a639e_720w.jpg\"></figure><p>图4</p><p>这里以英文字符的ASCII码作为比较准则。聚集索引这种实现方式使得按主键的搜索十分高效，但是辅助索引搜索需要检索两遍索引：首先检索辅助索引获得主键，然后用主键到主索引中检索获得记录。</p><p>&nbsp;</p><p>了解不同存储引擎的索引实现方式对于正确使用和优化索引都非常有帮助，例如知道了InnoDB的索引实现后，就很容易明白为什么不建议使用过长的字段作为主键，因为所有辅助索引都引用主索引，过长的主索引会令辅助索引变得过大。</p><p>&nbsp;</p><p>再例如，用非单调的字段作为主键在InnoDB中不是个好主意，因为InnoDB数据文件本身是一颗B+Tree，非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整，十分低效，而使用自增字段作为主键则是一个很好的选择。</p><p>&nbsp;</p><p><strong>数据查询方面优化</strong></p><p>在每一个消耗大量时间的查询案例中，都能看到一些不必要的额外操作、某些操作被额外地重复了很多次、某些操作执行得太慢等。优化查询的目的就是减少和消除这些操作所花费的时间。</p><p>一、首选要优化数据访问</p><p>查询性能底下最基本的原因是访问的数据太多。所以，对于低效的查询，一般通过两个步骤来分析：</p><p>确认应用程序是否在检索大量超过需要的数据。这通常意味着访问了太多的行，但有时候也可能是访问了太多的列。确认MySQL服务器层是否在分析大量超过需要的数据行。</p><p>1.1、是否向数据库请求了不需要的数据</p><p>在访问数据库时，应该只请求需要的行和列，请求多余的行和列会消耗MySQL服务器的CPU和内存资源，并增加网络开销。</p><p>1、在处理分页时，应该使用LIMIT限制MySQL只返回需要的数据，而不是向应用程序返回全部数据后，再由应用程序过滤不需要的行。</p><p>2、多表关联时，或获取单表数据时，尽量避免不加思考地使用SELECT *</p><p>3、当一些数据被多次使用时可以考虑将数据缓存起来，避免每次使用都要到MySQL查询。</p><p>1.2、MySQL是否在扫描额外的记录，应该让MySQL使用最合适的方式查询数据</p><p>对于MySQL，最简单的衡量查询开销有三个指标：响应时间、扫描的行数和返回的行数。这里主要考虑提高扫描的方式，即查询数据的方式。</p><p>&nbsp;</p><p>查询数据的方式有全表扫描、索引扫描、范围扫描、唯一索引查询、常数引用等。这些查询方式，速度从慢到快，扫描的行数也是从多到少。可以通过EXPLAIN语句中的type列反应查询采用的是哪种方式。</p><p>通常可以通过添加合适的索引改善查询数据的方式，使其尽可能减少扫描的数据行，加快查询速度。</p><p>例如，当发现查询需要扫描大量的数据行但只返回少数的行，那么可以考虑使用覆盖索引，即把所有需要用到的列都放到索引中。这样存储引擎无须回表获取对应行就可以返回结果了。</p><p>&nbsp;</p><p>二、重构查询的方法</p><p>设计查询的时候需要考虑是否需要把一个复杂的查询分成多个简单的查询。在我的印象中，曾经无数次听到一个经验法则：可以在数据库中做的事不要放在应用程序中，数据库比我们想象的要厉害的多。这个经验法则是在华夏基金使用Oracle编写SQL时一位Oracle牛人告诉我的，后来我把它使用到MySQL上，真是吃尽苦头。</p><p>当然这其中的原因有Oracle和MySQL原本就不是一样的处理逻辑，并且现在的网络通信、查询解析和优化的代价并没有以前那么高啦。再次说明，经验法则有在某种特定笼子里才有效。</p><p>&nbsp;</p><p><strong>分解复杂的查询：</strong></p><p>可以将一个大查询切分成多个小查询执行，每个小查询只完成整个查询任务的一小部分，每次只返回一小部分结果。</p><p>删除旧的数据是一个很好的例子。</p><p>如果只用一条语句一次性执行一个大的删除操作，则可能需要一次锁住很多数据，占满整个事务日志，耗尽系统资源、阻塞很多小的但重要的查询。将一个大的删除操作分解成多个较小的删除操作可以将服务器上原本一次性的压力分散到多次操作上，尽可能小地影响MySQL性能，减少删除时锁的等待时间，同时也减少了MySQL主从复制的延迟。这个方法我一直在用。</p><p>&nbsp;</p><p>另一个例子是分解关联查询，即对每个要关联的表进行单表查询，然后将结果在应用程序中进行关联。我在之前一家公司和一位在阿里待过很多年的同事一起编码时，他就是这么干的。后来我在心中默默地鄙视着他，因为我心里有这么一个经验法则（可以在数据库中做的事不要放在应用程序中，数据库比我们想象的要厉害的多），并且我在行动上也是保持能用一个SQL解决的事绝对不会用两个SQL。</p><p>&nbsp;</p><p>这么做当然处理经验法则的原因之外还有一个原因是：获取数据的逻辑尽量与业务代码分离，这样以后在切换数据库时也很方便。实际上是这样吗？未必啊。那次的无知让我吃尽苦头啊，后来因为SQL的性能问题再把我写的大部分SQL进行分解。</p><p><strong>用分解关联查询的方式重构查询有如下的优势：</strong></p><p>让缓存的效率更高。许多应用程序可以方便地缓存单表查询对应的结果对象。将查询分解后，执行单个查询可以减少锁的竞争。在应用层做关联，可以更容易对数据库进行拆分，更容易做到高性能和可扩展。查询本身效率也可能会有所提升。可以减少冗余记录的查询。在应用层做关联查询，</p><p>&nbsp;</p><p>意味着对于某条记录应用只需要查询一次，而在数据库中做关联查询，则可能需要重复地访问一部分数据。从这点看，这样的重构还可能会减少网络和内存的消耗。更进一步，这样做相当于在应用中实现了哈希关联，而不是使用MySQL的嵌套循环关联。某些场景哈希关联的效率要高很多。</p><p>&nbsp;</p><p><strong>数据库设计方面优化</strong></p><p>1、数据库设计符合第三范式，为了查询方便可以有一定的数据冗余。 2、选择数据类型优先级 int &gt; date,time &gt; enum,char&gt;varchar &gt; blob，选择数据类型时，可以考虑替换，如ip地址可以用ip2long()函数转换为unsign int型来进行存储。 3、对于char(n)类型，在数据完整的情况下尽量较小的的n值。 4、在建表时用partition命令对单个表分区可以大大提升查询效率，MySQL支持RANGE，LIST，HASH，KEY分区类型，其中以RANGE最为常用，分区方式为： 　　CREATE TABLE tablename{ 　　}ENGINE innodb/myisam CHARSET utf8 //选择数据库引擎和编码 　　PARTITION BY RANGE/LIST(column),//按范围和预定义列表进行分区 　　PARTITION partname VALUES LESS THAN /IN(n),//命名分区并详细限定分区的范围 5、选择数据库引擎时要注意innodb 和 myisam的区别。 　　存储结构：MyISAM在磁盘上存储成三个文件。而InnoDB所有的表都保存在同一个数据文件中，一般为2GB 　　事务支持：MyISAM不提供事务支持。InnoDB提供事务支持事务。 　　表锁差异：MyISAM只支持表级锁。InnoDB支持事务和行级锁。 　　全文索引：MyISAM支持 FULLTEXT类型的全文索引(不适用中文，所以要用sphinx全文索引引擎)。InnoDB不支持。 　　表的具体行数：MyISAM保存有表的总行数，查询count(*)很快。InnoDB没有保存表的总行数,需要重新计算。 　　外键：MyISAM不支持。InnoDB支持</p><p><strong>几条MySQL小技巧</strong></p><p>1、SQL语句中的关键词最好用大写来书写，第一易于区分关键词和操作对象，第二，SQL语句在执行时，MySQL会将其转换为大写，手动写大写能增加查询效率(虽然很小)。</p><p>2、如果我们们经对数据库中的数据行进行增删，那么会出现数据ID过大的情况，用ALTER TABLE tablename AUTO_INCREMENT=N，使自增ID从N开始计数。</p><p>3、对int类型添加 ZEROFILL 属性可以对数据进行自动补0</p><p>4、导入大量数据时最好先删除索引再插入数据，再加入索引，不然，mysql会花费大量时间在更新索引上。</p><p>5、创建数据库书写sql语句时 ，我们可以在IDE里创建一个后缀为.sql的文件，IDE会识别sql语法，更易于书写。更重要的是，如果你的数据库丢失了，你还可以找到这个文件，在当前目录下使用/path/mysql -uusername -ppassword databasename &lt; filename.sql来执行整个文件的sql语句（注意-u和-p后紧跟用户名密码，无空格）。</p><p><strong>以上内容希望帮助到大家，</strong>&nbsp;很多PHPer在进阶的时候总会遇到一些问题和瓶颈，业务代码写多了没有方向感，不知道该从那里入手去提升，对此我整理了一些资料，包括但不限于：分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6，laravel，Redis，Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家&nbsp;<strong>，需要戳这里</strong>&nbsp;&nbsp;&nbsp;&nbsp; <a href=\"https://docs.qq.com/doc/DUEZEWEN0cVZicVRW\"><strong>PHP进阶架构师&gt;&gt;&gt;实战视频、大厂面试文档免费获取</strong></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>', '/uploads/page/20200921/4b18ecfb4ac985005f305aa542239225.jpg', 1, '[2, 6]', 16, '2020-09-21 18:04:24', 'now', 1, 561, 1, 0, 'now', 'now', 1, 1, '2020-09-01 18:39:20', '2020-09-21 11:09:25');
INSERT INTO `page` VALUES (2, 3, 'k3s 进入 CNCF 沙箱，首个进入 CNCF 的 k8s 发行版', '8 月 31 日，Rancher 发布公告，宣布其开源项目 k3s 已经进入 CNCF 沙箱孵化，CNCF 沙箱是早期阶段项目的孵化器，当项目满足沙箱阶段的要求或者孵化阶段的附加要求时，即可进入孵化阶段。', '<p>8 月 31 日，Rancher 发布公告，宣布其开源项目 <a href=\"https://mp.weixin.qq.com/s?__biz=MzIyMTUwMDMyOQ==&amp;mid=2247494570&amp;idx=1&amp;sn=8f8e5866e647bbcb586510a220645f6e\">k3s 已经进入&nbsp;CNCF 沙箱孵化</a>，CNCF 沙箱是早期阶段项目的孵化器，当项目满足沙箱阶段的要求或者孵化阶段的附加要求时，即可进入孵化阶段。</p><p>目前在 CNCF 沙箱项目列表中也已经可以见到 k3s：<a href=\"https://www.cncf.io/sandbox-projects/\">https://www.cncf.io/sandbox-projects</a></p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-5a993d4fe23ecf3763cc08ed48bb1f6b40f.png\"></figure><p>k3s 是一个轻量级 Kubernetes，适用于 Edge、IoT、CI 与 ARM 场景。k3s 旨在成为完全兼容的 Kubernetes 发行版，相比 k8s 主要更改如下：</p><ol><li>旧的、Alpha 版本的、非默认功能都已经删除。</li><li>删除了大多数内部云提供商和存储插件，可以用插件替换。</li><li>新增 SQLite3 作为默认存储机制，etcd3 仍然有效，但是不再是默认项。</li><li>封装在简单的启动器中，可以处理大量 LTS 复杂性和选项。</li><li>最小化到没有操作系统依赖，只需要一个内核和 cgroup 挂载。</li></ol><p>这也是进入 CNCF 的首个 k8s 发行版。根据官方数据，自 2019 年 2 月发布，k3s 的全球下载量超过 100 万次，每周平均被安装超过 2 万次，其中 30% 的下载量来自于中国。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-d0920492431a0009b252f24546fc29f7440.png\"></figure><p>关于 k3s 进入 CNCF 沙箱，此前在提交提案期间引发了一些辩论，有人质疑 k3s 是否应改为 Kubernetes 的子项目，而不是作为独立项目进入 CNCF，不过最终得出结论是，k3s 目前有理由作为一个独立的项目，详情可以查看：<a href=\"https://lists.cncf.io/g/cncf-toc/message/5081\">https://lists.cncf.io/g/cncf-toc/message/5081</a></p>', '/uploads/page/20200921/88f9a38989cd6c37de457d2030aa3176.jpg', 1, '[4, 11]', 38, '2020-09-21 17:49:54', 'now', 1, 456, 1, 0, 'now', 'now', 1, 2, '2020-09-01 18:40:53', '2020-09-23 10:27:21');
INSERT INTO `page` VALUES (3, 1, 'Hyperf 发布 v2.0.9 版本，企业级的 PHP 微服务云原生协程框架', '本周主要新增了一些特性，并修复了一些组件的 🐛Bug，继续提升 Hyperf 的稳定性，发布于 2.0.9 版，建议用户使用以下命令更新此版本。', '<h2><strong>更新内容</strong></h2><p>本周主要新增了一些特性，并修复了一些组件的 🐛Bug，继续提升 Hyperf 的稳定性，发布于 <a href=\"https://github.com/hyperf/hyperf/releases/tag/v2.0.9\">2.0.9</a> 版，建议用户使用以下命令更新此版本。</p><p>composer update \"hyperf/*\" -o</p><p>直接访问 官网 <a href=\"https://hyperf.io/\">hyperf.io</a> 或 文档 <a href=\"https://hyperf.wiki/\">hyperf.wiki</a> 查看更新内容</p><h2><strong>新增</strong></h2><ul><li><a href=\"https://github.com/hyperf/hyperf/pull/2331\">#2331</a> <a href=\"https://github.com/hyperf/nacos\">hyperf/nacos</a> 组件增加授权接口。</li><li><a href=\"https://github.com/hyperf/hyperf/pull/2331\">#2331</a> <a href=\"https://github.com/hyperf/nacos\">hyperf/nacos</a> 组件增加 nacos.enable 配置，用于控制是否启用 Nacos 服务。</li><li><a href=\"https://github.com/hyperf/hyperf/pull/2331\">#2331</a> <a href=\"https://github.com/hyperf/nacos\">hyperf/nacos</a> 组件增加配置合并类型，默认使用全量覆盖。</li><li><a href=\"https://github.com/hyperf/hyperf/pull/2377\">#2377</a> 为 gRPC 客户端 的 request 增加 ts 请求头，以兼容 Node.js gRPC server 等。</li><li><a href=\"https://github.com/hyperf/hyperf/pull/2384\">#2384</a> 新增助手函数 optional()，以创建 Hyperf\\Utils\\Optional 对象或更方便 Optional 的使用。</li></ul><h2><strong>修改</strong></h2><ul><li><a href=\"https://github.com/hyperf/hyperf/pull/2331\">#2331</a> 修复 <a href=\"https://github.com/hyperf/nacos\">hyperf/nacos</a> 组件，服务或配置不存在时，会抛出异常的问题。</li><li><a href=\"https://github.com/hyperf/hyperf/pull/2356\">#2356</a> <a href=\"https://github.com/hyperf/hyperf/pull/2368\">#2368</a> 修复 pid_file 被用户修改后，命令行 server:start 启动失败的问题。</li><li><a href=\"https://github.com/hyperf/hyperf/pull/2358\">#2358</a> 修复验证器规则 digits 不支持 int 类型的问题。</li></ul><h2><strong>优化</strong></h2><ul><li><a href=\"https://github.com/hyperf/hyperf/pull/2359\">#2359</a> 优化自定义进程，在协程风格服务下，可以更加友好的停止。</li><li><a href=\"https://github.com/hyperf/hyperf/pull/2363\">#2363</a> 优化 <a href=\"https://github.com/hyperf/di\">hyperf/di</a> 组件，使其不需要依赖 <a href=\"https://github.com/hyperf/config\">hyperf/config</a> 组件。</li><li><a href=\"https://github.com/hyperf/hyperf/pull/2373\">#2373</a> 优化 <a href=\"https://github.com/hyperf/validation\">hyperf/validation</a> 组件的异常捕获器，使其返回 Response 时，自动添加 content-type 头。</li></ul><h2><strong>关于 Hyperf</strong></h2><p>Hyperf 是基于 Swoole 4.5+ 实现的高性能、高灵活性的 PHP 协程框架，内置协程服务器及大量常用的组件，性能较传统基于 PHP-FPM 的框架有质的提升，提供超高性能的同时，也保持着极其灵活的可扩展性，标准组件均基于 <a href=\"https://www.php-fig.org/psr\">PSR 标准</a> 实现，基于强大的依赖注入设计，保证了绝大部分组件或类都是 可替换 与 可复用 的。</p><p>框架组件库除了常见的协程版的 MySQL 客户端、Redis 客户端，还为您准备了协程版的 Eloquent ORM、WebSocket 服务端及客户端、JSON RPC 服务端及客户端、GRPC 服务端及客户端、OpenTracing(Zipkin, Jaeger) 客户端、Guzzle HTTP 客户端、Elasticsearch 客户端、Consul、Nacos 服务中心、ETCD 客户端、AMQP 组件、Nats 组件、Apollo、ETCD、Zookeeper、Nacos 和阿里云 ACM 的配置中心、基于令牌桶算法的限流器、通用连接池、熔断器、Swagger 文档生成、Swoole Tracker、Blade、Smarty、Twig、Plates 和 ThinkTemplate 视图引擎、Snowflake 全局ID生成器、Prometheus 服务监控 等组件，省去了自己实现对应协程版本的麻烦。</p><p>Hyperf 还提供了 基于 PSR-11 的依赖注入容器、注解、AOP 面向切面编程、基于 PSR-15 的中间件、自定义进程、基于 PSR-14 的事件管理器、Redis/RabbitMQ 消息队列、自动模型缓存、基于 PSR-16 的缓存、Crontab 秒级定时任务、Session、i18n 国际化、Validation 表单验证 等非常便捷的功能，满足丰富的技术场景和业务场景，开箱即用。</p><h2><strong>框架初衷</strong></h2><p>尽管现在基于 PHP 语言开发的框架处于一个百花争鸣的时代，但仍旧未能看到一个优雅的设计与超高性能的共存的完美框架，亦没有看到一个真正为 PHP 微服务铺路的框架，此为 Hyperf 及其团队成员的初衷，我们将持续投入并为此付出努力，也欢迎你加入我们参与开源建设。</p><h2><strong>设计理念</strong></h2><p>Hyperspeed + Flexibility = Hyperf，从名字上我们就将 超高速 和 灵活性 作为 Hyperf 的基因。</p><ul><li>对于超高速，我们基于 Swoole 协程并在框架设计上进行大量的优化以确保超高性能的输出。</li><li>对于灵活性，我们基于 Hyperf 强大的依赖注入组件，组件均基于 <a href=\"https://www.php-fig.org/psr\">PSR 标准</a> 的契约和由 Hyperf 定义的契约实现，达到框架内的绝大部分的组件或类都是可替换的。</li></ul><p>基于以上的特点，Hyperf 将存在丰富的可能性，如实现 单体 Web 服务，API 服务，网关服务，分布式中间件，微服务架构，游戏服务器，物联网（IOT）等。</p><h2><strong>文档齐全</strong></h2><p>我们投入了大量的时间用于文档的建设以提供高质量的文档体验，以解决各种因为文档缺失所带来的问题，文档上也提供了大量的示例，对新手同样友好。<br><a href=\"https://hyperf.wiki/\">Hyperf 官方开发文档</a></p><h2><strong>生产可用</strong></h2><p>我们为组件进行了大量的单元测试以保证逻辑的正确，目前存在 1485 个单测共 4623 个断言条件，Hyperf 是一款经历过严酷的生产环境考验的一个项目，目前已有很多的大型互联网企业都已将 Hyperf 部署到了自己的生产环境上并稳定运行。</p><h2><strong>官网及交流</strong></h2><p><a href=\"https://github.com/hyperf/hyperf\">Github</a> 👈👈👈👈👈 点 Star 支持我们<br><a href=\"https://gitee.com/hyperf/hyperf\">Gitee 码云</a> 👈👈👈👈👈 点 Star 支持我们<br><a href=\"https://hyperf.io/\">Hyperf 官网</a><br><a href=\"https://hyperf.wiki/\">Hyperf 文档</a></p>', '/uploads/page/20200921/184d64b2ea96d6956a95f1b68dd51333.jpg', 1, '[1, 2]', 66, '2020-09-21 17:49:38', 'now', 1, 46, 1, 0, 'now', 'now', 1, 1, '2020-09-01 18:42:07', '2020-09-23 10:36:24');
INSERT INTO `page` VALUES (4, 3, 'FastAPI 0.61.1 发布，Python 高性能 Web 框架', 'FastAPI 0.61.1 发布了，FastAPI 是一个高性能 Web 框架，用于构建 API。修复直接将 jsonable_encoder 与 SQLAlchemy 模型一起使用时的问题，修复 NoSQL 文档中的拼写错误，为主页添加日语翻译，通过更新 hl_lines 语法以提高文档的可维护性', '<p>FastAPI 0.61.1 发布了，FastAPI 是一个高性能 Web 框架，用于构建 API。</p><p>更新内容：</p><ul><li>修复直接将 jsonable_encoder 与 SQLAlchemy 模型一起使用时的问题</li><li>修复 NoSQL 文档中的拼写错误</li><li>为主页添加日语翻译</li><li>初始化法语翻译</li><li>初始化土耳其语翻译</li><li>通过更新 hl_lines 语法以提高文档的可维护性</li></ul><p>更新说明：<a href=\"https://github.com/tiangolo/fastapi/releases/tag/0.61.1\">https://github.com/tiangolo/fastapi/releases/tag/0.61.1</a></p>', '/uploads/page/20200921/0f6ebe1d30fee6a406e969d3252805bc.jpg', 1, '[10, 11]', 58, '2020-09-21 17:49:23', 'now', 1, 345, 0, 0, 'now', 'now', 1, 5, '2020-09-01 18:43:14', '2020-09-23 10:27:12');
INSERT INTO `page` VALUES (5, 3, '一次完整的JVM堆外内存泄漏故障排查记录', '记录一次线上JVM堆外内存泄漏问题的排查过程与思路，其中夹带一些「JVM内存分配的原理分析」以及「常用的JVM问题排查手段和工具分享」，希望对大家有所帮助。记录一次线上JVM堆外内存泄漏问题的排查过程与思路，其中夹带一些「JVM内存分配的原理分析」以及「常用的JVM问题排查手段和工具分享」，希望对大家有所帮助。', '<h2><br><strong>前言</strong></h2><p>记录一次线上JVM堆外内存泄漏问题的排查过程与思路，其中夹带一些<strong>「JVM内存分配的原理分析」</strong>以及<strong>「常用的JVM问题排查手段和工具分享」</strong>，希望对大家有所帮助。</p><p>在整个排查过程中，我也走了不少弯路，但是在文章中我仍然会把完整的思路和想法写出来，当做一次经验教训，给后人参考，文章最后也总结了下内存泄漏问题快速排查的几个原则。</p><p><strong>「本文的主要内容：」</strong></p><ul><li>故障描述和排查过程</li><li>故障原因和解决方案分析</li><li>JVM堆内内存和堆外内存分配原理</li><li>常用的进程内存泄漏排查指令和工具介绍和使用</li></ul><blockquote><p><strong>❝</strong></p><p>文章撰写不易，请大家多多支持我的原创技术公众号：后端技术漫谈</p><p>❞</p></blockquote><h2><strong>故障描述</strong></h2><p>8月12日中午午休时间，我们商业服务收到告警，服务进程占用容器的物理内存（16G）超过了80%的阈值，并且还在不断上升。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/fcad2cc7-c60e-4b12-9095-df09f956a388.png\"></figure><p>监控系统调出图表查看：</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/e82579a8-5f59-4358-88d9-41c7f14a4f33.png\"></figure><p>像是Java进程发生了内存泄漏，而我们堆内存的限制是4G，这种大于4G快要吃满内存应该是JVM堆外内存泄漏。</p><p>确认了下当时服务进程的启动配置：</p><p>-Xms4g&nbsp;-Xmx4g&nbsp;-Xmn2g&nbsp;-Xss1024K&nbsp;-XX:PermSize=256m&nbsp;-XX:MaxPermSize=512m&nbsp;-XX:ParallelGCThreads=20&nbsp;-XX:+UseConcMarkSweepGC&nbsp;-XX:+UseParNewGC&nbsp;-XX:+UseCMSCompactAtFullCollection&nbsp;-XX:CMSInitiatingOccupancyFraction=80</p><p>虽然当天没有上线新代码，但是<strong>「当天上午我们正在使用消息队列推送历史数据的修复脚本，该任务会大量调用我们服务其中的某一个接口」</strong>，所以初步怀疑和该接口有关。</p><p>下图是该调用接口当天的访问量变化：</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/d84b064b-9afe-49e5-91e7-c6204212a471.png\"></figure><p>可以看到案发当时调用量相比正常情况（每分钟200+次）提高了很多（每分钟5000+次）。</p><p><strong>「我们暂时让脚本停止发送消息，该接口调用量下降到每分钟200+次，容器内存不再以极高斜率上升，一切似乎恢复了正常。」</strong></p><p>接下来排查这个接口是不是发生了内存泄漏。</p><h2><strong>排查过程</strong></h2><p>首先我们先回顾下Java进程的内存分配，方便我们下面排查思路的阐述。</p><p><strong>「以我们线上使用的JDK1.8版本为例」</strong>。JVM内存分配网上有许多总结，我就不再进行二次创作。</p><p>JVM内存区域的划分为两块：堆区和非堆区。</p><ul><li>堆区：就是我们熟知的新生代老年代。</li><li>非堆区：非堆区如图中所示，有元数据区和直接内存。</li></ul><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/dd32edf0-9585-4406-82a8-380960a5a80b.png\"></figure><p><strong>「这里需要额外注意的是：永久代（JDK8的原生去）存放JVM运行时使用的类，永久代的对象在full GC时进行垃圾收集。」</strong></p><p>复习完了JVM的内存分配，让我们回到故障上来。</p><h3><strong>堆内存分析</strong></h3><p>虽说一开始就基本确认与堆内存无关，因为泄露的内存占用超过了堆内存限制4G，但是我们为了保险起见先看下堆内存有什么线索。</p><p>我们观察了新生代和老年代内存占用曲线以及回收次数统计，和往常一样没有大问题，我们接着在事故现场的容器上dump了一份JVM堆内存的日志。</p><h4><strong>堆内存Dump</strong></h4><p>堆内存快照dump命令：</p><p>jmap&nbsp;-dump:live,format=b,file=xxxx.hprof&nbsp;pid</p><blockquote><p><strong>❝</strong></p><p>画外音：你也可以使用jmap -histo:live pid直接查看堆内存存活的对象。</p><p>❞</p></blockquote><p>导出后，将Dump文件下载回本地，然后可以使用Eclipse的MAT（Memory Analyzer）或者JDK自带的JVisualVM打开日志文件。</p><p>使用MAT打开文件如图所示：</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/6435c027-0050-4fea-8bd7-a02b754d62b0.png\"></figure><p><strong>「可以看到堆内存中，有一些nio有关的大对象，比如正在接收消息队列消息的nioChannel，还有nio.HeapByteBuffer，但是数量不多，不能作为判断的依据，先放着观察下。」</strong></p><p>下一步，我开始浏览该接口代码，接口内部主要逻辑是调用集团的WCS客户端，将数据库表中数据查表后写入WCS，没有其他额外逻辑</p><p>发觉没有什么特殊逻辑后，我开始怀疑WCS客户端封装是否存在内存泄漏，这样怀疑的理由是，WCS客户端底层是由SCF客户端封装的，作为RPC框架，其底层通讯传输协议有可能会申请直接内存。</p><p><strong>「是不是我的代码出发了WCS客户端的Bug，导致不断地申请直接内存的调用，最终吃满内存。」</strong></p><p>我联系上了WCS的值班人，将我们遇到的问题和他们描述了一下，他们回复我们，会在他们本地执行下写入操作的压测，看看能不能复现我们的问题。</p><p>既然等待他们的反馈还需要时间，我们就准备先自己琢磨下原因。</p><p><strong>「我将怀疑的目光停留在了直接内存上，怀疑是由于接口调用量过大，客户端对nio使用不当，导致使用ByteBuffer申请过多的直接内存。」</strong></p><blockquote><p><strong>❝</strong></p><p><strong>「画外音：最终的结果证明，这一个先入为主的思路导致排查过程走了弯路。在问题的排查过程中，用合理的猜测来缩小排查范围是可以的，但最好先把每种可能性都列清楚，在发现自己深入某个可能性无果时，要及时回头仔细审视其他可能性。」</strong></p><p>❞</p></blockquote><h3><strong>沙箱环境复现</strong></h3><p>为了能还原当时的故障场景，我在沙箱环境申请了一台压测机器，来确保和线上环境一致。</p><p><strong>「首先我们先模拟内存溢出的情况（大量调用接口）：」</strong></p><p>我们让脚本继续推送数据，调用我们的接口，我们持续观察内存占用。</p><p>当开始调用后，内存便开始持续增长，并且看起来没有被限制住（没有因为限制触发Full GC）。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/42fff7ef-2782-44a0-8d94-6f8a3ae286b6.png\"></figure><p><strong>「接着我们来模拟下平时正常调用量的情况（正常量调用接口）：」</strong></p><p>我们将该接口平时正常的调用量（比较小，且每10分钟进行一次批量调用）切到该压测机器上，得到了下图这样的老生代内存和物理内存趋势：</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/582cff45-6c3e-47ab-a26b-96caad8a7b24.png\"></figure><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/a44c750c-5726-4b7f-8e33-011929092109.png\"></figure><p><strong>「问题来了：为何内存会不断往上走吃满内存呢？」</strong></p><p>当时猜测是由于JVM进程并没有对于直接内存大小进行限制（-XX:MaxDirectMemorySize），所以堆外内存不断上涨，并不会触发FullGC操作。</p><p><strong>「上图能够得出两个结论：」</strong></p><ul><li>在内存泄露的接口调用量很大的时候，如果恰好堆内老生代等其他情况一直不满足FullGC条件，就一直不会FullGC，直接内存一路上涨。</li><li>而在平时低调用量的情况下， 内存泄漏的比较慢，FullGC总会到来，回收掉泄露的那部分，这也是平时没有出问题，正常运行了很久的原因。</li></ul><p><strong>「由于上面提到，我们进程的启动参数中并没有限制直接内存，于是我们将-XX:MaxDirectMemorySize配置加上，再次在沙箱环境进行了测验。」</strong></p><p>结果发现，进程占用的物理内存依然会不断上涨，超出了我们设置的限制，“看上去”配置似乎没起作用。</p><p>这让我很讶异，难道JVM对内存的限制出现了问题？</p><p><strong>「到了这里，能够看出我排查过程中思路执着于直接内存的泄露，一去不复返了。」</strong></p><blockquote><p><strong>❝</strong></p><p><strong>「画外音：我们应该相信JVM对内存的掌握，如果发现参数失效，多从自己身上找原因，看看是不是自己使用参数有误。」</strong></p><p>❞</p></blockquote><h3><strong>直接内存分析</strong></h3><p>为了更进一步的调查清楚直接内存里有什么，我开始对直接内存下手。由于直接内存并不能像堆内存一样，很容易的看出所有占用的对象，我们需要一些命令来对直接内存进行排查，我有用了几种办法，来查看直接内存里到底出现了什么问题。</p><h4><strong>查看进程内存信息 pmap</strong></h4><p>pmap - report memory map of a process(查看进程的内存映像信息)</p><p>pmap命令用于报告进程的内存映射关系，是Linux调试及运维一个很好的工具。</p><p>pmap&nbsp;-x&nbsp;pid&nbsp;如果需要排序&nbsp;&nbsp;|&nbsp;sort&nbsp;-n&nbsp;-k3**</p><p>执行后我得到了下面的输出，删减输出如下:</p><p>..</p><p>00007fa2d4000000&nbsp;&nbsp;&nbsp;&nbsp;8660&nbsp;&nbsp;&nbsp;&nbsp;8660&nbsp;&nbsp;&nbsp;&nbsp;8660&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa65f12a000&nbsp;&nbsp;&nbsp;&nbsp;8664&nbsp;&nbsp;&nbsp;&nbsp;8664&nbsp;&nbsp;&nbsp;&nbsp;8664&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa610000000&nbsp;&nbsp;&nbsp;&nbsp;9840&nbsp;&nbsp;&nbsp;&nbsp;9832&nbsp;&nbsp;&nbsp;&nbsp;9832&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa5f75ff000&nbsp;&nbsp;&nbsp;10244&nbsp;&nbsp;&nbsp;10244&nbsp;&nbsp;&nbsp;10244&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa6005fe000&nbsp;&nbsp;&nbsp;59400&nbsp;&nbsp;&nbsp;10276&nbsp;&nbsp;&nbsp;10276&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa3f8000000&nbsp;&nbsp;&nbsp;10468&nbsp;&nbsp;&nbsp;10468&nbsp;&nbsp;&nbsp;10468&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa60c000000&nbsp;&nbsp;&nbsp;10480&nbsp;&nbsp;&nbsp;10480&nbsp;&nbsp;&nbsp;10480&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa614000000&nbsp;&nbsp;&nbsp;10724&nbsp;&nbsp;&nbsp;10696&nbsp;&nbsp;&nbsp;10696&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa6e1c59000&nbsp;&nbsp;&nbsp;13048&nbsp;&nbsp;&nbsp;11228&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;r-x--&nbsp;libjvm.so</p><p>00007fa604000000&nbsp;&nbsp;&nbsp;12140&nbsp;&nbsp;&nbsp;12016&nbsp;&nbsp;&nbsp;12016&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa654000000&nbsp;&nbsp;&nbsp;13316&nbsp;&nbsp;&nbsp;13096&nbsp;&nbsp;&nbsp;13096&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa618000000&nbsp;&nbsp;&nbsp;16888&nbsp;&nbsp;&nbsp;16748&nbsp;&nbsp;&nbsp;16748&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa624000000&nbsp;&nbsp;&nbsp;37504&nbsp;&nbsp;&nbsp;18756&nbsp;&nbsp;&nbsp;18756&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa62c000000&nbsp;&nbsp;&nbsp;53220&nbsp;&nbsp;&nbsp;22368&nbsp;&nbsp;&nbsp;22368&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa630000000&nbsp;&nbsp;&nbsp;25128&nbsp;&nbsp;&nbsp;23648&nbsp;&nbsp;&nbsp;23648&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa63c000000&nbsp;&nbsp;&nbsp;28044&nbsp;&nbsp;&nbsp;24300&nbsp;&nbsp;&nbsp;24300&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa61c000000&nbsp;&nbsp;&nbsp;42376&nbsp;&nbsp;&nbsp;27348&nbsp;&nbsp;&nbsp;27348&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa628000000&nbsp;&nbsp;&nbsp;29692&nbsp;&nbsp;&nbsp;27388&nbsp;&nbsp;&nbsp;27388&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa640000000&nbsp;&nbsp;&nbsp;28016&nbsp;&nbsp;&nbsp;28016&nbsp;&nbsp;&nbsp;28016&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa620000000&nbsp;&nbsp;&nbsp;28228&nbsp;&nbsp;&nbsp;28216&nbsp;&nbsp;&nbsp;28216&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa634000000&nbsp;&nbsp;&nbsp;36096&nbsp;&nbsp;&nbsp;30024&nbsp;&nbsp;&nbsp;30024&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa638000000&nbsp;&nbsp;&nbsp;65516&nbsp;&nbsp;&nbsp;40128&nbsp;&nbsp;&nbsp;40128&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa478000000&nbsp;&nbsp;&nbsp;46280&nbsp;&nbsp;&nbsp;46240&nbsp;&nbsp;&nbsp;46240&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>0000000000f7e000&nbsp;&nbsp;&nbsp;47980&nbsp;&nbsp;&nbsp;47856&nbsp;&nbsp;&nbsp;47856&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa67ccf0000&nbsp;&nbsp;&nbsp;52288&nbsp;&nbsp;&nbsp;51264&nbsp;&nbsp;&nbsp;51264&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa6dc000000&nbsp;&nbsp;&nbsp;65512&nbsp;&nbsp;&nbsp;63264&nbsp;&nbsp;&nbsp;63264&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00007fa6cd000000&nbsp;&nbsp;&nbsp;71296&nbsp;&nbsp;&nbsp;68916&nbsp;&nbsp;&nbsp;68916&nbsp;rwx--&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>00000006c0000000&nbsp;4359360&nbsp;2735484&nbsp;2735484&nbsp;rw---&nbsp;&nbsp;&nbsp;[&nbsp;anon&nbsp;]</p><p>可以看出，最下面一行是堆内存的映射，占用4G，其他上面有非常多小的内存占用，不过通过这些信息我们依然看不出问题。</p><h4><strong>堆外内存跟踪 NativeMemoryTracking</strong></h4><blockquote><p><strong>❝</strong></p><p>Native Memory Tracking (NMT) 是Hotspot VM用来分析VM内部内存使用情况的一个功能。我们可以利用jcmd（jdk自带）这个工具来访问NMT的数据。</p><p>❞</p></blockquote><p>NMT必须先通过VM启动参数中打开，不过要注意的是，打开NMT会带来5%-10%的性能损耗。</p><p>-XX:NativeMemoryTracking=[off&nbsp;|&nbsp;summary&nbsp;|&nbsp;detail]</p><p>#&nbsp;off:&nbsp;默认关闭</p><p>#&nbsp;summary:&nbsp;只统计各个分类的内存使用情况.</p><p>#&nbsp;detail:&nbsp;Collect&nbsp;memory&nbsp;usage&nbsp;by&nbsp;individual&nbsp;call&nbsp;sites.</p><p>然后运行进程，可以使用下面的命令查看直接内存：</p><p>jcmd&nbsp;&lt;pid&gt;&nbsp;VM.native_memory&nbsp;[summary&nbsp;|&nbsp;detail&nbsp;|&nbsp;baseline&nbsp;|&nbsp;summary.diff&nbsp;|&nbsp;detail.diff&nbsp;|&nbsp;shutdown]&nbsp;[scale=&nbsp;KB&nbsp;|&nbsp;MB&nbsp;|&nbsp;GB]</p><p>&nbsp;</p><p>#&nbsp;summary:&nbsp;分类内存使用情况.</p><p># detail:&nbsp;详细内存使用情况，除了summary信息之外还包含了虚拟内存使用情况。</p><p>#&nbsp;baseline:&nbsp;创建内存使用快照，方便和后面做对比</p><p>#&nbsp;summary.diff:&nbsp;和上一次baseline的summary对比</p><p>#&nbsp;detail.diff:&nbsp;和上一次baseline的detail对比</p><p>#&nbsp;shutdown:&nbsp;关闭NMT</p><p>我们使用：</p><p>jcmd&nbsp;pid&nbsp;VM.native_memory&nbsp;detail&nbsp;scale=MB&nbsp;&gt;&nbsp;temp.txt</p><p>得到如图结果：</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/93dd8ea9-c260-429a-be50-fbe44ac31513.png\"></figure><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/aa8ed5ae-f2d4-43d1-96ac-c2a54b1b4633.png\"></figure><p>上图中给我们的信息，都不能很明显的看出问题，至少我当时依然不能通过这几次信息看出问题。</p><p>排查似乎陷入了僵局。</p><h3><strong>山重水复疑无路</strong></h3><p>在排查陷入停滞的时候，我们得到了来自WCS和SCF方面的回复，<strong>「两方都确定了他们的封装没有内存泄漏的存在」</strong>，WCS方面没有使用直接内存，而SCF虽然作为底层RPC协议，但是也不会遗留这么明显的内存bug，否则应该线上有很多反馈。</p><h4><strong>查看JVM内存信息 jmap</strong></h4><p>此时，找不到问题的我再次新开了一个沙箱容器，运行服务进程，然后运行jmap命令，看一看JVM内存的<strong>「实际配置」</strong>：</p><p>jmap&nbsp;-heap&nbsp;pid</p><p>得到结果：</p><p>Attaching&nbsp;to&nbsp;process&nbsp;ID&nbsp;1474,&nbsp;please&nbsp;wait...</p><p>Debugger&nbsp;attached&nbsp;successfully.</p><p>Server&nbsp;compiler&nbsp;detected.</p><p>JVM&nbsp;version&nbsp;is&nbsp;25.66-b17</p><p>using&nbsp;parallel&nbsp;threads&nbsp;</p><p><strong>in</strong></p><p>&nbsp;the&nbsp;new&nbsp;generation.</p><p>using&nbsp;thread-local&nbsp;object&nbsp;allocation.</p><p>Concurrent&nbsp;Mark-Sweep&nbsp;GC</p><p>Heap&nbsp;Configuration:</p><p>&nbsp;&nbsp;&nbsp;MinHeapFreeRatio&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;40</p><p>&nbsp;&nbsp;&nbsp;MaxHeapFreeRatio&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;70</p><p>&nbsp;&nbsp;&nbsp;MaxHeapSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;4294967296&nbsp;(4096.0MB)</p><p>&nbsp;&nbsp;&nbsp;NewSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;2147483648&nbsp;(2048.0MB)</p><p>&nbsp;&nbsp;&nbsp;MaxNewSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;2147483648&nbsp;(2048.0MB)</p><p>&nbsp;&nbsp;&nbsp;OldSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;2147483648&nbsp;(2048.0MB)</p><p>&nbsp;&nbsp;&nbsp;NewRatio&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;2</p><p>&nbsp;&nbsp;&nbsp;SurvivorRatio&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;8</p><p>&nbsp;&nbsp;&nbsp;MetaspaceSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;21807104&nbsp;(20.796875MB)</p><p>&nbsp;&nbsp;&nbsp;CompressedClassSpaceSize&nbsp;=&nbsp;1073741824&nbsp;(1024.0MB)</p><p>&nbsp;&nbsp;&nbsp;MaxMetaspaceSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;17592186044415&nbsp;MB</p><p>&nbsp;&nbsp;&nbsp;G1HeapRegionSize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0&nbsp;(0.0MB)</p><p>Heap&nbsp;Usage:</p><p>New&nbsp;Generation&nbsp;(Eden&nbsp;+&nbsp;1&nbsp;Survivor&nbsp;Space):</p><p>&nbsp;&nbsp;&nbsp;capacity&nbsp;=&nbsp;1932787712&nbsp;(1843.25MB)</p><p>&nbsp;&nbsp;&nbsp;used&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;1698208480&nbsp;(1619.5378112792969MB)</p><p>&nbsp;&nbsp;&nbsp;free&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;234579232&nbsp;(223.71218872070312MB)</p><p>&nbsp;&nbsp;&nbsp;87.86316621615607%&nbsp;used</p><p>Eden&nbsp;Space:</p><p>&nbsp;&nbsp;&nbsp;capacity&nbsp;=&nbsp;1718091776&nbsp;(1638.5MB)</p><p>&nbsp;&nbsp;&nbsp;used&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;1690833680&nbsp;(1612.504653930664MB)</p><p>&nbsp;&nbsp;&nbsp;free&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;27258096&nbsp;(25.995346069335938MB)</p><p>&nbsp;&nbsp;&nbsp;98.41346682518548%&nbsp;used</p><p>From&nbsp;Space:</p><p>&nbsp;&nbsp;&nbsp;capacity&nbsp;=&nbsp;214695936&nbsp;(204.75MB)</p><p>&nbsp;&nbsp;&nbsp;used&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;7374800&nbsp;(7.0331573486328125MB)</p><p>&nbsp;&nbsp;&nbsp;free&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;207321136&nbsp;(197.7168426513672MB)</p><p>&nbsp;&nbsp;&nbsp;3.4349974840697497%&nbsp;used</p><p>To&nbsp;Space:</p><p>&nbsp;&nbsp;&nbsp;capacity&nbsp;=&nbsp;214695936&nbsp;(204.75MB)</p><p>&nbsp;&nbsp;&nbsp;used&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0&nbsp;(0.0MB)</p><p>&nbsp;&nbsp;&nbsp;free&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;214695936&nbsp;(204.75MB)</p><p>&nbsp;&nbsp;&nbsp;0.0%&nbsp;used</p><p>concurrent&nbsp;mark-sweep&nbsp;generation:</p><p>&nbsp;&nbsp;&nbsp;capacity&nbsp;=&nbsp;2147483648&nbsp;(2048.0MB)</p><p>&nbsp;&nbsp;&nbsp;used&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;322602776&nbsp;(307.6579818725586MB)</p><p>&nbsp;&nbsp;&nbsp;free&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;1824880872&nbsp;(1740.3420181274414MB)</p><p>&nbsp;&nbsp;&nbsp;15.022362396121025%&nbsp;used</p><p>29425&nbsp;interned&nbsp;Strings&nbsp;occupying&nbsp;3202824&nbsp;bytes</p><p>输出的信息中，看得出老年代和新生代都蛮正常的，元空间也只占用了20M，直接内存看起来也是2g...</p><p>嗯？为什么MaxMetaspaceSize = 17592186044415 MB？<strong>「看起来就和没限制一样」</strong>。</p><p>再仔细看看我们的启动参数：</p><p>-Xms4g&nbsp;-Xmx4g&nbsp;-Xmn2g&nbsp;-Xss1024K&nbsp;-XX:PermSize=256m&nbsp;-XX:MaxPermSize=512m&nbsp;-XX:ParallelGCThreads=20&nbsp;-XX:+UseConcMarkSweepGC&nbsp;-XX:+UseParNewGC&nbsp;-XX:+UseCMSCompactAtFullCollection&nbsp;-XX:CMSInitiatingOccupancyFraction=80</p><p>配置的是-XX:PermSize=256m -XX:MaxPermSize=512m，也就是永久代的内存空间。<strong>「而1.8后，Hotspot虚拟机已经移除了永久代，使用了元空间代替。」</strong> 由于我们线上使用的是JDK1.8，<strong>「所以我们对于元空间的最大容量根本就没有做限制」</strong>，-XX:PermSize=256m -XX:MaxPermSize=512m 这两个参数对于1.8就是过期的参数。</p><p>下面的图描述了从1.7到1.8，永久代的变更：</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/ad210596-a86b-4505-95b8-d6d2e76b52ae.png\"></figure><p><strong>「那会不会是元空间内存泄露了呢？」</strong></p><p>我选择了在本地进行测试，方便更改参数，也方便使用JVisualVM工具直观的看出内存变化。</p><h4><strong>使用JVisualVM观察进程运行</strong></h4><p>首先限制住元空间，使用参数-XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m，然后在本地循环调用出问题的接口。</p><p>得到如图：</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/6c1f295b-bc4a-4fcb-b40b-55060e4e6935.png\"></figure><p><strong>「可以看出，在元空间耗尽时，系统出发了Full GC，元空间内存得到回收，并且卸载了很多类。」</strong></p><p>然后我们将元空间限制去掉，也就是使用之前出问题的参数：</p><p>-Xms4g&nbsp;-Xmx4g&nbsp;-Xmn2g&nbsp;-Xss1024K&nbsp;-XX:ParallelGCThreads=20&nbsp;-XX:+UseConcMarkSweepGC&nbsp;-XX:+UseParNewGC&nbsp;-XX:+UseCMSCompactAtFullCollection&nbsp;-XX:CMSInitiatingOccupancyFraction=80&nbsp;-XX:MaxDirectMemorySize=2g&nbsp;-XX:+UnlockDiagnosticVMOptions</p><p>得到如图：</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/19b37123-c335-40c1-b78f-4a26e27342ec.png\"></figure><p><strong>「可以看出，元空间在不断上涨，并且已装入的类随着调用量的增加也在不断上涨，呈现正相关趋势。」</strong></p><h3><strong>柳暗花明又一村</strong></h3><p>问题一下子明朗了起来，<strong>「随着每次接口的调用，极有可能是某个类都在不断的被创建，占用了元空间的内存」</strong>。</p><h4><strong>观察JVM类加载情况 -verbose</strong></h4><blockquote><p><strong>❝</strong></p><p>在调试程序时，有时需要查看程序加载的类、内存回收情况、调用的本地接口等。这时候就需要-verbose命令。在myeclipse可以通过右键设置（如下），也可以在命令行输入java -verbose来查看。</p><p>❞</p></blockquote><p>-verbose:class&nbsp;查看类加载情况</p><p>-verbose:gc&nbsp;查看虚拟机中内存回收情况</p><p>-verbose:jni&nbsp;查看本地方法调用的情况</p><p>我们在本地环境，添加启动参数-verbose:class循环调用接口。</p><p>可以看到生成了无数com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto:</p><p>[Loaded&nbsp;com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto&nbsp;from&nbsp;file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar]</p><p>[Loaded&nbsp;com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto&nbsp;from&nbsp;file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar]</p><p>[Loaded&nbsp;com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto&nbsp;from&nbsp;file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar]</p><p>[Loaded&nbsp;com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto&nbsp;from&nbsp;file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar]</p><p>[Loaded&nbsp;com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto&nbsp;from&nbsp;file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar]</p><p>[Loaded&nbsp;com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto&nbsp;from&nbsp;file:/C:/Users/yangzhendong01/.m2/repository/com/alibaba/fastjson/1.2.71/fastjson-1.2.71.jar]</p><p>当调用了很多次，积攒了一定的类时，我们手动执行Full GC，进行类加载器的回收，我们发现大量的fastjson相关类被回收。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/84f9c26b-dbf5-4143-8513-dae217a44b81.png\"></figure><p><strong>「如果在回收前，使用jmap查看类加载情况，同样也可以发现大量的fastjson相关类：」</strong></p><p>jmap&nbsp;-clstats&nbsp;7984</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/da73f576-4177-49af-907c-e3422dcaac1a.png\"></figure><p>这下有了方向，<strong>「这次仔细排查代码」</strong>，查看代码逻辑里哪里用到了fastjson，发现了如下代码：</p><p>/**</p><p>&nbsp;*&nbsp;返回Json字符串.驼峰转_</p><p>&nbsp;*&nbsp;@param&nbsp;bean&nbsp;实体类.</p><p>&nbsp;*/</p><p>public&nbsp;static&nbsp;String&nbsp;buildData(Object&nbsp;bean)&nbsp;{</p><p>&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SerializeConfig&nbsp;CONFIG&nbsp;=&nbsp;new&nbsp;SerializeConfig();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CONFIG.propertyNamingStrategy&nbsp;=&nbsp;PropertyNamingStrategy.SnakeCase;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;jsonString&nbsp;=&nbsp;JSON.toJSONString(bean,&nbsp;CONFIG);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(Exception&nbsp;e)&nbsp;{</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;null;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;}</p><p>}</p><h3><strong>问题根因</strong></h3><p>我们在调用wcs前将驼峰字段的实体类序列化成下划线字段，**这需要使用fastjson的SerializeConfig，而我们在静态方法中对其进行了实例化。SerializeConfig创建时默认会创建一个ASM代理类用来实现对目标对象的序列化。也就是上面被频繁创建的类com.alibaba.fastjson.serializer.ASMSerializer_1_WlkCustomerDto,如果我们复用SerializeConfig，fastjson会去寻找已经创建的代理类，从而复用。但是如果new SerializeConfig()，则找不到原来生成的代理类，就会一直去生成新的WlkCustomerDto代理类。</p><p>下面两张图时问题定位的源码：</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/f0abfb18-4eb2-46bf-a7d8-ff0ad20520bb.png\"></figure><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/97492c80-f726-488b-8e5f-fa0ba1e023c0.png\"></figure><p>我们将SerializeConfig作为类的静态变量，问题得到了解决。</p><p>private&nbsp;static&nbsp;final&nbsp;SerializeConfig&nbsp;CONFIG&nbsp;=&nbsp;new&nbsp;SerializeConfig();</p><p>static&nbsp;{</p><p>&nbsp;&nbsp;&nbsp;&nbsp;CONFIG.propertyNamingStrategy&nbsp;=&nbsp;PropertyNamingStrategy.SnakeCase;</p><p>}</p><h4><strong>fastjson SerializeConfig 做了什么</strong></h4><p>SerializeConfig介绍：</p><blockquote><p><strong>❝</strong></p><p>SerializeConfig的主要功能是配置并记录每种Java类型对应的序列化类（ObjectSerializer接口的实现类），比如Boolean.class使用BooleanCodec（看命名就知道该类将序列化和反序列化实现写到一起了）作为序列化实现类，float[].class使用FloatArraySerializer作为序列化实现类。这些序列化实现类，有的是FastJSON中默认实现的（比如Java基本类），有的是通过ASM框架生成的（比如用户自定义类），有的甚至是用户自定义的序列化类（比如Date类型框架默认实现是转为毫秒，应用需要转为秒）。当然，这就涉及到是使用ASM生成序列化类还是使用JavaBean的序列化类类序列化的问题，这里判断根据就是是否Android环境（环境变量\"java.vm.name\"为\"dalvik\"或\"lemur\"就是Android环境），但判断不仅这里一处，后续还有更具体的判断。</p><p>❞</p></blockquote><p>理论上来说，每个SerializeConfig实例若序列化相同的类，都会找到之前生成的该类的代理类，来进行序列化。们的服务在每次接口被调用时，都实例化一个ParseConfig对象来配置Fastjson反序列的设置，而未禁用ASM代理的情况下，由于每次调用ParseConfig都是一个新的实例，因此永远也检查不到已经创建的代理类，所以Fastjson便不断的创建新的代理类，并加载到metaspace中，最终导致metaspace不断扩张，将机器的内存耗尽。</p><h4><strong>升级JDK1.8才会出现问题</strong></h4><p>导致问题发生的原因还是值得重视。为什么在升级之前不会出现这个问题？这就要分析jdk1.8和1.7自带的hotspot虚拟机的差异了。</p><blockquote><p><strong>❝</strong></p><p>从jdk1.8开始，自带的hostspot虚拟机取消了过去的永久区，而新增了metaspace区，从功能上看，metaspace可以认为和永久区类似，其最主要的功用也是存放类元数据，但实际的机制则有较大的不同。</p><p>首先，metaspace默认的最大值是整个机器的物理内存大小，所以metaspace不断扩张会导致java程序侵占系统可用内存，最终系统没有可用的内存；而永久区则有固定的默认大小，不会扩张到整个机器的可用内存。当分配的内存耗尽时，两者均会触发full gc，但不同的是永久区在full gc时，以堆内存回收时类似的机制去回收永久区中的类元数据（Class对象），只要是根引用无法到达的对象就可以回收掉，而metaspace判断类元数据是否可以回收，是根据加载这些类元数据的Classloader是否可以回收来判断的，只要Classloader不能回收，通过其加载的类元数据就不会被回收。这也就解释了我们这两个服务为什么在升级到1.8之后才出现问题，因为在之前的jdk版本中，虽然每次调用fastjson都创建了很多代理类，在永久区中加载类很多代理类的Class实例，但这些Class实例都是在方法调用是创建的，调用完成之后就不可达了，因此永久区内存满了触发full gc时，都会被回收掉。</p><p>而使用1.8时，因为这些代理类都是通过主线程的Classloader加载的，这个Classloader在程序运行的过程中永远也不会被回收，因此通过其加载的这些代理类也永远不会被回收，这就导致metaspace不断扩张，最终耗尽机器的内存了。</p><p>❞</p></blockquote><p>这个问题并不局限于fastjson，只要是需要通过程序加载创建类的地方，就有可能出现这种问题。<strong>「尤其是在框架中，往往大量采用类似ASM、javassist等工具进行字节码增强，而根据上面的分析，在jdk1.8之前，因为大多数情况下动态加载的Class都能够在full gc时得到回收，因此不容易出现问题」</strong>，也因此很多框架、工具包并没有针对这个问题做一些处理，一旦升级到1.8之后，这些问题就可能会暴露出来。</p><h2><strong>总结</strong></h2><p>问题解决了，接下来复盘下整个排查问题的流程，整个流程暴露了我很多问题，最主要的就是<strong>「对于JVM不同版本的内存分配还不够熟悉」</strong>，导致了对于老生代和元空间判断失误，走了很多弯路，在直接内存中排查了很久，浪费了很多时间。</p><p>其次，排查需要的<strong>「一是仔细，二是全面，」</strong>，最好将所有可能性先行整理好，不然很容易陷入自己设定好的排查范围内，走进死胡同不出来。</p><p>最后，总结一下这次的问题带来的收获：</p><ul><li>JDK1.8开始，自带的hostspot虚拟机取消了过去的永久区，而新增了metaspace区，从功能上看，metaspace可以认为和永久区类似，其最主要的功用也是存放类元数据，但实际的机制则有较大的不同。</li><li>对于JVM里面的内存需要在启动时进行限制，包括我们熟悉的堆内存，也要包括直接内存和元生区，这是保证线上服务正常运行最后的兜底。</li><li>使用类库，请多注意代码的写法，尽量不要出现明显的内存泄漏。</li><li>对于使用了ASM等字节码增强工具的类库，在使用他们时请多加小心（尤其是JDK1.8以后）。</li></ul><blockquote><p><strong>❝</strong></p><p>文章撰写不易，请大家多多支持我的原创技术公众号：后端技术漫谈</p><p>❞</p></blockquote><h2><strong>参考</strong></h2><p>观察程序运行时类加载的过程</p><p>blog.csdn.net/tenderhearted/article/details/39642275</p><p>Metaspace整体介绍（永久代被替换原因、元空间特点、元空间内存查看分析方法）</p><p>https://www.cnblogs.com/duanxz/p/3520829.html</p><p>java内存占用异常问题常见排查流程（含堆外内存异常）</p><p>https://my.oschina.net/haitaohu/blog/3024843</p><p>JVM源码分析之堆外内存完全解读</p><p>http://lovestblog.cn/blog/2015/05/12/direct-buffer/</p><p>JVM 类的卸载</p><p>https://www.cnblogs.com/caoxb/p/12735525.html</p><p>fastjson在jdk1.8上面开启asm</p><p>https://github.com/alibaba/fastjson/issues/385</p><p>fastjson：PropertyNamingStrategy_cn</p><p>https://github.com/alibaba/fastjson/wiki/PropertyNamingStrategy_cn</p><p>警惕动态代理导致的Metaspace内存泄漏问题</p><p>https://blog.csdn.net/xyghehehehe/article/details/78820135</p><h2><strong>关注我</strong></h2><p>我是一名后端开发工程师。主要关注后端开发，数据安全，爬虫，物联网，边缘计算等方向，欢迎交流。</p><h3><strong>各大平台都可以找到我</strong></h3><ul><li><strong>「微信公众号：后端技术漫谈」</strong></li><li><strong>「Github：@qqxx6661」</strong></li><li>CSDN：@蛮三刀把刀</li><li>知乎：@后端技术漫谈</li><li>简书：@蛮三刀把刀</li><li>掘金：@蛮三刀把刀</li><li>腾讯云+社区：@后端技术漫谈</li></ul><h3><strong>原创文章主要内容</strong></h3><ul><li>后端开发实战</li><li>Java面试知识</li><li>设计模式/数据结构/算法题解</li><li>读书笔记/逸闻趣事/程序人生</li></ul>', '/uploads/page/20200921/974d5558f0bb5667d9d836cd7db25041.jpg', 1, '[10, 11]', 13, '2020-09-21 18:02:47', 'now', 1, 47, 0, 0, 'now', 'now', 1, 1, '2020-09-01 18:45:21', '2020-09-23 10:27:16');
INSERT INTO `page` VALUES (6, 3, 'Linux 迎来 29 岁：从个人爱好到统治世界的操作系统内核', '1991 年的 8 月 25 日，来自芬兰赫尔辛基大学的 Linus Torvalds 用 Minix 操作平台建立了一个新的操作系统内核，并把它发回 Minix Usenet 新闻组。此时，年仅 21 岁的大学生 Linus 不会意识到，自己当做兴趣爱好开发的一个小项目会在 29 年后发展成统治世界的庞大操作系统内核。', '<p>1991 年的 8 月 25 日，来自芬兰赫尔辛基大学的 Linus Torvalds 用 Minix 操作平台建立了一个新的操作系统内核，并把它发回 Minix Usenet 新闻组。此时，年仅 21 岁的大学生 Linus 不会意识到，自己当做兴趣爱好开发的一个小项目会在 29 年后发展成统治世界的庞大操作系统内核。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-0921d85bce5f876704b42afecc07144e4f9.png\" alt=\"\"></figure><p>在 Linux 正式对外公布的 29 周年之际， ZDNet 资深编辑 Steven J. Vaughan-Nichols 整理了 Linux 29 年历史所经历的重大事件。下面就让我们一起来看看 Linux 如何一步步从一个大学生的业余爱好成长为今天这个庞大的操作系统内核。</p><blockquote><p><a href=\"https://www.zdnet.com/pictures/linux-turns-29-the-biggest-events-in-its-history-so-far/\">Linux 29 年历史重大事件整理</a></p><p>By&nbsp;<a href=\"https://www.zdnet.com/meet-the-team/us/steven-j-vaughan-nichols/\">Steven J. Vaughan-Nichols</a></p></blockquote><p><strong>1991 年</strong> —— Linus&nbsp;Torvalds 向全世界介绍 Linux</p><p>图中这条消息是在 1991 年 8 月 25 日发回 Minix Usenet 新闻组的。当 Linus Torvalds 在谈到他的新的免费操作系统时，他并不知道自己写的这个东西会在未来变成什么，他写道：“ 这只是出于我的个人爱好，不会像 GNU 那样成为 386(486) AT 克隆的那样大而专业的系统。\"</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-da05fcb0ec0505e85eadad7cde11495826a.png\" alt=\"\"></figure><p><strong>1992 年</strong> —— Linux 面临的第一次战争</p><p>操作系统大师、Unix 的教育操作系统版本 Minix 的创造者 Andrew Tannenbaum 宣称 “Linux 已经过时了”，Linux 面临的第一次操作系统战争开始了。在由此引发的讨论中，Linus Torvalds 对他对 Linux 的愿景做了一个很有说服力的评论，这个评论在今天仍然是正确的，“ 如果 GNU 内核（另一个创建类似 Unix 的自由操作系统的项目）在去年春天就已经准备好了，我甚至不会费心去启动我的项目。然而事实是，它没有，现在仍然没有。Linux 在现在可用的点上赢得了很大的优势。\"</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-18c2558005bca422ac50e44478d1ca00c9d.png\" alt=\"\"></figure><p><strong>1993 年</strong> —— Slackware Linux 发行</p><p>早期有一些 Linux 发行版，如 MCC 和 Yggdrasil Linux，但 Patrick Volkerding 的 Slackware 是第一个广泛成功的 Linux 发行版，它至今仍在更新和使用。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-ecdaf9f041b8283723f4756505869149c14.png\" alt=\"\"></figure><p><strong>1993 年</strong> —— Debian Linux 诞生</p><p>Debian Linux，流行的社区版 Linux，是由它开始的。今天，它是 Mint、Ubuntu 和许多其他流行的 Linux 发行版的基础。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-c91fdd80f61b7d1a4f43dccad304a8da680.JPEG\" alt=\"\"></figure><p><strong>1994 年</strong> —— 红帽公司成立</p><p>Marc Ewing 创建了红帽 Linux。Bob Young 收购了 Ewing 的公司，将其与自己的公司合并，并组建了红帽，这是迄今为止最成功的 Linux 公司。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-21db75b8efce7d0c62ed004d05a8a566a4e.JPEG\" alt=\"\"></figure><p><strong>1995 年</strong> —— 首届 Linux 博览会开幕</p><p>这一年，Linux 有了第一个贸易会议，Linux 博览会。之后还诞生了更多的展会。今天，仅在美国就有十多个主要的地区性和全国性的 Linux 贸易展。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-0a801fc7818a85c6127b96db9a1850436fc.JPEG\" alt=\"\"></figure><p>&nbsp;</p><p><strong>1996 年</strong> —— 首个 Linux 桌面界面诞生</p><p>KDE 是第一个主要的 Linux 桌面界面，它于 1996 年由 Matthias Ettrich 创造。Matthias Ettrich 之所以创办它，是因为他想做一个易于使用的桌面。KDE中的 “K” 是 “Kool” 的意思。这个名字也是 Unix 的通用桌面环境（CDE）的一个近似变换。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-8117b8be30f1c5adaac6096522d98bb14a2.png\" alt=\"\"></figure><p><strong>1996 年</strong> —— SUSE Linux 发布</p><p>同样在 1996 年，在 Slackware 和红帽 Linux 合作后，欧洲顶级商用 Linux 厂商 SUSE 发布了其首款独立 Linux 发行版。如今 SUSE 依然是 Linux 和云计算领域的重要厂商。</p><p>&nbsp;</p><p><strong>1997 年</strong> —— GNOME</p><p>Miguel de Icaza 和 Federico Mena 开始着手开发一个新的 Linux 桌面，命名为 GNOME 。该桌面完全基于自由软件构建。GNOME 与 KDE 一起，将成为 Linux 最重要的两个桌面之一。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-16653edde4c101cdc428973cfa2b440b14b.png\" alt=\"\"></figure><p><strong>1998 年</strong> —— 微软的“万圣节文件”</p><p>Linux 的快速发展引起了专有操作系统巨头微软的重视。早期的 Linux 和开放源代码负责人 Eric S. Raymond 透露了一份来自微软内部的<a href=\"http://www.catb.org/~esr/halloween/halloween1.html)\">万圣节文件</a>，该<a href=\"http://www.catb.org/~esr/halloween/halloween1.html)\">文件</a>表明微软正认真对待 Linux 带来的市场威胁，将其视为竞争对手，并开始制定其反开放源代码和 Linux 运动的计划。然而十年后，微软将改变自己的腔调。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-09604e92d3bb2e50ea39bf9e654015ab011.png\" alt=\"\"></figure><p>&nbsp;</p><p><strong>1999 年</strong> —— Corel Linux 桌面</p><p>&nbsp;<a href=\"http://practical-tech.com/operating-system/corel-puts-a-penguin-the-desktop/293/?preview=true&amp;preview_id=293&amp;preview_nonce=a618c6de4b\">Corel 发布了第一个主流 Linux 桌面</a>。虽然不成功，但它将为其他流行的 Linux 桌面发行版铺平了道路，例如后来 Ubuntu 。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-7f66269493f38be1ea925045053027b3462.png\" alt=\"\"></figure><p>&nbsp;</p><p><strong>1999 年</strong> —— Linux 与微软 Windows 首次正面对决</p><p>Linux 首次在文件服务方面与 Windows NT 进行了基准测试。Linux 赢了。Linux 与 Windows 服务器操作系统的战争开始了。Linux 最终获胜。今天，Linux 在网络服务器和云计算领域都占据了主导地位。</p><p>&nbsp;</p><p><strong>2000 年</strong> —— IBM 向 Linux 投资 10 亿美元</p><p>在这一年，IBM 宣布将在 2001 年向 Linux 投资 10 亿美元。这将被证明是 IBM 有史以来最好的投资。通过此举，IBM 也打破了 Linux 在企业市场的僵局。</p><p>&nbsp;</p><p><strong>2001 年</strong> —— Linux 2.4 版本发布</p><p>经过一段时间的延迟，Linux 2.4 发布了。有了这个版本，Linux 成为与 Solaris 和其他高端服务器操作系统竞争的对象。</p><p>&nbsp;</p><p><strong>2003 年</strong> —— SOC 与 Linux 开战</p><p>由旧的 SCO Unix 公司和 Caldera Linux 业务组成的 SCO 系统出现，但 SCO 背弃了自己的Linux 历史，起诉 IBM 和其他公司，试图证明 Linux 是 Unix 的复制品。该公司失败了，但在一段时间里其 FUD 一直阻挠着 Linux 的商业接受度。</p><p>&nbsp;</p><p><strong>2004 年</strong> —— Ubuntu 来了</p><p>Ubuntu 诞生了。在 Debian Linux 的基础上，Ubuntu 成为了一个非常流行的 Linux 桌面操作系统，也是所有云 Linux 发行版中最重要的一个。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-b5f6f6aea3b17a1e36b117bd7c782d79996.png\" alt=\"\"></figure><p>&nbsp;</p><p><strong>2004 年</strong> —— Linux 统治超级计算机</p><p>此时，在世界上最快的超级计算机中，超过一半运行着 Linux。到了 2017 年，<a href=\"https://www.zdnet.com/article/linux-totally-dominates-supercomputers/\">所有的超级计算机都将运行 Linux</a>。</p><p>&nbsp;</p><p><strong>2005 年</strong> —— Linux 商业化的成功</p><p>Linus Torvalds 首次出现在了《商业周刊》的封面上，打破了人们对 Linux 成为主要商业参与者的任何怀疑。广告语是什么？Linux Inc. 今天，你很难找到任何不在 Linux 上运行的大型企业。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-b6fd6c5f4960449ffd1d7e9cf1c0085b985.png\" alt=\"\"></figure><p><strong>2007 年</strong> —— 基于 Linux 打造的 Android 系统诞生</p><p>包括谷歌和众多硬件厂商在内的开放手机联盟宣布推出 Android 系统。它将成为最受欢迎的移动端用户操作系统，因为它在超过 10 亿部智能手机上运行。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-1445de4e9044a4730d7247048f9d9b6c6c6.png\" alt=\"\"></figure><p>&nbsp;</p><p><strong>2008 年</strong> —— 证券交易所系统转移到 Linux</p><p>纽约证券交易所改用 Linux 作为核心操作系统，这一举措很快就被世界上许多其他主要证券交易所效仿。Linux 并没有成为大生意，Linux 本身就是大生意。</p><p>&nbsp;</p><p><strong>2011 年</strong> —— 谷歌推出 Chromebook</p><p>谷歌推出首款 Chromebook，CR-48。它运行基于 Gentoo-Linux 的 ChromeOS。到 2015 年，Chromebook 在教育市场等轻办公领域的销量已经超过了 Windows 笔记本。</p><p>&nbsp;</p><p><strong>2012 年</strong> —— 云运行在 Linux 之上</p><p>IT 产业开始从服务器和数据中心转移到云端，而云端设备运行在 Linux 上。到 2019 年，即使在微软 Azure 上，微软客户的虚拟机(VM)实例也有一半以上运行 Linux。</p><p>&nbsp;</p><p><strong>2012 年</strong> —— 红帽身价达到 10 亿美元</p><p>红帽成为第一家十亿美元的开源公司。2016 年，它成为第一家价值 20 亿美元的 Linux 企业。</p><p>&nbsp;</p><p><strong>2014 年</strong> —— 微软 “示爱” Linux</p><p>微软新任 CEO Satya Nadella 宣称，“ 微软热爱 Linux ”。随后，微软通过在云端和内部部署支持 Linux 和开源软件来证明这一点，逐渐走上拥抱开源之路。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-ee88b3990ce8a7ed5f7a53e93fec2a5c2c3.png\" alt=\"\"></figure><p><strong>2018 年</strong> —— 微软将其专利组合开源</p><p>这可能是微软有史以来最激进的支持开源的举动，微软将其整个专利组合向开放发明网络（OIN）开源专利联盟的成员开放。OIN 是为 Linux 的所有专利进行辩护的非营利组织。</p><p>&nbsp;</p><p><strong>2019 年</strong> —— 微软为 Windows 10 用户推出 Linux</p><p>微软紧接着为 Windows 10 用户推出了自己的原生 Linux —— Windows Subsystem for Linux 2.0。有了它，人们可以将 Linux 与 Windows 同时运行。</p><p>&nbsp;</p><p><strong>2019 年</strong> —— IBM 斥资 340 亿美元收购红帽</p><p>红帽被 IBM 以 340 亿美元收购，成为有史以来最大的软件收购案。从 IBM 的这一举动不难看出Linux 如今在科技界的主导地位。</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-ce2bd3283bda0b558232159eba76275cb95.png\" alt=\"\"></figure><p><strong>2020 年</strong> —— Linux 统治云计算</p><p>全球云计算市场每年超过 1000 亿美元。其中 90% 的云端设备运行在 Linux 上。</p><p>现在，Linux 与开源社区的故事仍在继续……</p>', '/uploads/page/20200921/1f7d891010e0fd439bc333b365ec2609.jpg', 1, '[11]', 9, '2020-09-21 17:48:42', 'now', 1, 85, 0, 0, 'now', 'now', 1, 5, '2020-09-01 18:48:42', '2020-09-21 16:54:16');
INSERT INTO `page` VALUES (7, 1, 'RXThinkCMF_TP6 v2.8.0 旗舰版发布，新增操作日志和登录日志功能', 'RXThinkCMF_TP6_PRO旗舰版 基于 ThinkPHP6 +Layui2.5.6 开发权限(RBAC)及内容管理框架，框架中集成了权限管理、模块管理、插件管理、钩子管理、数据库管理、富文本编辑器(已集成ueditor,kindeditor)，后台支持多主题切换、布局管理、广告管理、配置管理、字典管理、切图管理、CMS内容管理等常用功能模块，以方便开发者快速构建自己的应用。', '<p>v2.8.0版本更新</p><p>1、【新增】新增记录操作日志的功能；</p><p>2、【新增】新增系统登录日志的功能，详细记录登录用户名、登录IP、登录时间、登录地点；</p><p>3、【修复】修复近期系统使用过程中发现的BUG并做了优化升级</p><p>4、【解决】解决人员管理模块访问时间较长的问题，对人员模块重点优化、移除不必要的业务实现；</p><p>&nbsp;</p><p>RXThinkCMF_TP6_PRO旗舰版 基于 ThinkPHP6 +Layui2.5.6 开发权限(RBAC)及内容管理框架，框架中集成了权限管理、模块管理、插件管理、钩子管理、数据库管理、富文本编辑器(已集成ueditor,kindeditor)，后台支持多主题切换、布局管理、广告管理、配置管理、字典管理、切图管理、CMS内容管理等常用功能模块，以方便开发者快速构建自己的应用。RXThinkCMF_TP6_PRO框架专注于为中小企业提供最佳的行业基础后台框架解决方案，执行效率、扩展性、稳定性值得信赖，操作体验流畅，使用非常优化，欢迎大家使用及进行二次开发。</p><ul><li>模块化：全新的架构和模块化的开发机制，便于灵活扩展和二次开发。</li><li>模型/栏目/分类信息体系：通过栏目和模型绑定，以及不同的模型类型，不同栏目可以实现差异化的功能，轻松实现诸如资讯、下载、讨论和图片等功能。通过分类信息和栏目绑定，可以自动建立索引表，轻松实现复杂的信息检索。</li><li>RXThinkCMF_TP6_PRO是一套基于ThinkPHP + Layui开发出来的框架。</li><li>支持SQLServer、MySQL、Oracle、PostgreSQL、SQLite等多数据库类型。模块化设计，层次结构清晰。</li><li>AUTH权限认证，操作权限控制精密细致，对所有管理链接都进行权限验证，可控制到导航菜单、功能按钮。提高开发效率及质量。</li><li>常用类封装，日志、缓存、验证、字典、文件（本地、七牛云）。等等，目前兼容浏览器（Chrome、Firefox、360浏览器等）</li><li>适用范围：可以开发OA、ERP、BPM、CRM、WMS、TMS、MIS、BI、电商平台后台、物流管理系统、快递管理系统、教务管理系统等各类管理软件。</li></ul><h2><strong>环境要求:</strong></h2><ul><li>PHP &gt;= 7.0</li><li>PDO PHP Extension</li><li>MBstring PHP Extension</li><li>CURL PHP Extension</li><li>开启静态重写</li><li>要求环境支持pathinfo</li><li>要求安装Zip扩展(插件/模块市场需要)</li></ul><h3><strong>功能特性</strong></h3><ul><li><strong>严谨规范：</strong> 提供一套有利于团队协作的结构设计、编码、数据等规范。</li><li><strong>高效灵活：</strong> 清晰的分层设计、钩子行为扩展机制，解耦设计更能灵活应对需求变更。</li><li><strong>严谨安全：</strong> 清晰的系统执行流程，严谨的异常检测和安全机制，详细的日志统计，为系统保驾护航。</li><li><strong>组件化：</strong> 完善的组件化设计，丰富的表单组件，让开发列表和表单更得心应手。无需前端开发，省时省力。</li><li><strong>简单上手快：</strong> 结构清晰、代码规范、在开发快速的同时还兼顾性能的极致追求。</li><li><strong>自身特色：</strong> 权限管理、组件丰富、第三方应用多、分层解耦化设计和先进的设计思想。</li><li><strong>高级进阶：</strong> 分布式、负载均衡、集群、Redis、分库分表。</li><li><strong>命令行：</strong> 命令行功能，一键管理应用扩展。</li></ul><h2><strong>开发者信息</strong></h2><ul><li>系统名称：RXThinkCMF_TP6_PRO权限(RBAC)及内容管理框架</li><li>作者[牧羊人]：南京RXThink研发工作室</li><li>官网网址：<a href=\"http://www.rxthink.cn/\">http://www.rxthink.cn/</a></li><li>文档网址：<a href=\"http://docs.v6.rxthink.cn/\">http://docs.v6.rxthink.cn/</a></li><li>开源协议：Apache 2.0</li></ul><h2><strong>后台演示（用户名:admin 密码:123456）</strong></h2><ul><li>RXThinkCMF_TP6_PRO版本：<a href=\"http://manage.pro6.rxthink.cn/\">http://manage.pro6.rxthink.cn/</a></li></ul><p><strong>专业版地址：</strong><a href=\"https://gitee.com/ruoxi520_admin/RXThinkCMF_TP6\"><strong>https://gitee.com/ruoxi520_admin/RXThinkCMF_TP6</strong></a></p><p>旗舰版地址：<a href=\"https://gitee.com/ruoxi520_admin/RXThinkCMF_TP6_PRO\">https://gitee.com/ruoxi520_admin/RXThinkCMF_TP6_PRO</a></p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/up-5185f07359eda68d6dc4abea41d97ebd422.png\" alt=\"\"></figure>', '/uploads/page/20200921/7b59987cba5e7d4fdbcc81ebc27c52ad.jpg', 1, '[10]', 25, '2020-09-21 19:07:58', 'now', 1, 342, 0, 0, 'now', 'now', 1, 1, '2020-09-01 18:50:42', '2020-09-23 09:53:31');
INSERT INTO `page` VALUES (8, 3, 'Node 脚本遭遇异常时如何安全退出', '一个 Node 相关的项目中，总是少不了跑脚本。跑一个脚本拉取配置、处理一些数据以及定时任务更是家常便饭。如果在这些重要流程中脚本出错无法及时发现问题，将有可能引发更加隐蔽的问题。', '<p>一个 Node 相关的项目中，总是少不了跑脚本。跑一个脚本拉取配置、处理一些数据以及定时任务更是家常便饭。</p><p>在一些重要流程中能够看到脚本的身影：</p><ol><li>CI，用以测试、质量保障及部署等</li><li>Docker，用以构建镜像</li><li>Cron，用以定时任务</li></ol><p>如果在这些重要流程中脚本出错无法及时发现问题，将有可能引发更加隐蔽的问题。</p><p>最近观察项目镜像构建，会偶尔发现一两个镜像虽然构建成功，但容器却跑不起来的情况。<strong>「究其原因，是因为 Exit Code 的问题」</strong>。</p><h2><strong>Exit Code</strong></h2><blockquote><p><strong>❝</strong></p><p>什么是 exit code?</p><p>❞</p></blockquote><p>exit code 代表一个进程的返回码，通过系统调用 exit_group 来触发。在 POSIX 中，0 代表正常的返回码，1-255 代表异常返回码，一般主动抛出的错误码都是 1。在 Node 应用中使用 process.exitCode = 1 来代表因不期望的异常而中断。</p><p>这里有一张关于异常码的附表 Appendix E. Exit Codes With Special Meanings[1]。</p><p>异常码在操作系统中随处可见，以下是一个关于 cat 命令的异常以及它的 exit code，并使用 strace 追踪系统调用。</p><p>$&nbsp;cat&nbsp;a</p><p>cat:&nbsp;a:&nbsp;No&nbsp;such&nbsp;file&nbsp;or&nbsp;directory</p><p><i>#&nbsp;使用&nbsp;strace&nbsp;查看&nbsp;cat&nbsp;的系统调用</i></p><p><i>#&nbsp;-e&nbsp;只显示&nbsp;write&nbsp;与&nbsp;exit_group&nbsp;的系统调用</i></p><p>$&nbsp;strace&nbsp;-e&nbsp;write,exit_group&nbsp;cat&nbsp;a</p><p>write(2,&nbsp;\"cat:&nbsp;\",&nbsp;5cat:&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;5</p><p>write(2,&nbsp;\"a\",&nbsp;1a)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;1</p><p>write(2,&nbsp;\":&nbsp;No&nbsp;such&nbsp;file&nbsp;or&nbsp;directory\",&nbsp;27:&nbsp;No&nbsp;such&nbsp;file&nbsp;or&nbsp;directory)&nbsp;=&nbsp;27</p><p>write(2,&nbsp;\"\\n\",&nbsp;1</p><p>)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;1</p><p>exit_group(1)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;?</p><p>+++&nbsp;exited&nbsp;with&nbsp;1&nbsp;+++</p><p>从系统调用的最后一行可以看出，该进行的 exit code 是 1，并把错误信息输出到 stderr (标准错误的 fd 为 2) 中</p><h2><strong>如何查看 exit code</strong></h2><p>从 strace 中可以来判断进程的 exit code，但是不够方便过于冗余，特别身处 shell 编程环境中。</p><p><strong>「有一种简单的方法，通过 echo $? 来确认返回码」</strong></p><p>$&nbsp;cat&nbsp;a</p><p>cat:&nbsp;a:&nbsp;No&nbsp;such&nbsp;file&nbsp;or&nbsp;directory</p><p>$&nbsp;echo&nbsp;$?</p><p>1</p><h2><strong>throw new Error与Promise.reject区别</strong></h2><p>以下是两段代码，第一段抛出一个异常，第二段 Promise.reject，两段代码都会如下打印出一段异常信息，那么两者有什么区别？</p><p>function&nbsp;error&nbsp;()&nbsp;{</p><p>&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(\'hello,&nbsp;error\')</p><p>}</p><p>error()</p><p><i>//&nbsp;Output:</i></p><p><i>//&nbsp;/Users/shanyue/Documents/note/demo.js:2</i></p><p><i>//&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;Error(\'hello,&nbsp;world\')</i></p><p><i>//&nbsp;&nbsp;&nbsp;^</i></p><p><i>//</i></p><p><i>//&nbsp;Error:&nbsp;hello,&nbsp;world</i></p><p><i>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;error&nbsp;(/Users/shanyue/Documents/note/demo.js:2:9)</i></p><p><i>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;Object.&lt;anonymous&gt;&nbsp;(/Users/shanyue/Documents/note/demo.js:5:1)</i></p><p><i>//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;Module._compile&nbsp;(internal/modules/cjs/loader.js:701:30)</i></p><p>async&nbsp;function&nbsp;error&nbsp;()&nbsp;{</p><p>&nbsp;&nbsp;return&nbsp;new&nbsp;Error(\'hello,&nbsp;error\')</p><p>}</p><p>error()</p><p><i>//&nbsp;Output:</i></p><p><i>//&nbsp;(node:60356)&nbsp;UnhandledPromiseRejectionWarning:&nbsp;Error:&nbsp;hello,&nbsp;world</i></p><p><i>//&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;error&nbsp;(/Users/shanyue/Documents/note/demo.js:2:9)</i></p><p><i>//&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;Object.&lt;anonymous&gt;&nbsp;(/Users/shanyue/Documents/note/demo.js:5:1)</i></p><p><i>//&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;Module._compile&nbsp;(internal/modules/cjs/loader.js:701:30)</i></p><p><i>//&nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;Object.Module._extensions..js&nbsp;(internal/modules/cjs/loader.js:712:10)</i></p><p><i>//&nbsp;(node:2787)&nbsp;UnhandledPromiseRejectionWarning:&nbsp;Unhandled&nbsp;promise&nbsp;rejection.&nbsp;This&nbsp;error&nbsp;originated&nbsp;either&nbsp;by&nbsp;throwing&nbsp;inside&nbsp;of&nbsp;an&nbsp;async&nbsp;function&nbsp;without&nbsp;a&nbsp;catch&nbsp;block,&nbsp;or&nbsp;by&nbsp;rejecting&nbsp;a&nbsp;promise&nbsp;which&nbsp;was&nbsp;not&nbsp;handled&nbsp;with&nbsp;.catch().&nbsp;To&nbsp;terminate&nbsp;the&nbsp;node&nbsp;process&nbsp;on&nbsp;unhandled&nbsp;promise&nbsp;rejection,&nbsp;use&nbsp;the&nbsp;CLI&nbsp;flag&nbsp;`--unhandled-rejections=strict`&nbsp;(see&nbsp;https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode).&nbsp;(rejection&nbsp;id:&nbsp;1)</i></p><p><i>//&nbsp;(node:2787)&nbsp;[DEP0018]&nbsp;DeprecationWarning:&nbsp;Unhandled&nbsp;promise&nbsp;rejections&nbsp;are&nbsp;deprecated.&nbsp;In&nbsp;the&nbsp;future,&nbsp;promise&nbsp;rejections&nbsp;that&nbsp;are&nbsp;not&nbsp;handled&nbsp;will&nbsp;terminate&nbsp;the&nbsp;Node.js&nbsp;process&nbsp;with&nbsp;a&nbsp;non-zero&nbsp;exit&nbsp;code.</i></p><p>在对上述两个测试用例使用 echo $? 查看 exit code，我们会发现 throw new Error() 的 exit code 为 1，而 Promise.reject() 的为 0。</p><p><strong>「从操作系统的角度来讲，exit code 为 0 代表进程成功运行并退出，此时即使有 Promise.reject，操作系统也会视为它执行成功。」</strong></p><p>这在 Dockerfile 与 CI 中将留有安全隐患。</p><h2><strong>Dockerfile 在 node 中的注意点</strong></h2><p>当使用 Dockerfile 构建镜像时，如果 RUN 的进程返回非 0 的返回码，构建就会失败。</p><p><strong>「而在 Node 中的错误处理中，我们倾向于所有的异常都交由 async/await 来处理，而当发生异常时，由于此时 exit code 为 0 并不会导致镜像构建失败。」</strong></p><p>这是一个浅显易懂的含 Promise.reject() 问题的镜像。</p><p>FROM&nbsp;node:12-alpine</p><p>RUN&nbsp;node&nbsp;-e&nbsp;\"Promise.reject(\'hello,&nbsp;world\')\"</p><p>构建镜像过程如下：<strong>「即使在构建过程打印出了 unhandledPromiseRejection 信息，但是镜像仍然构建成功。」</strong></p><p>$&nbsp;docker&nbsp;build&nbsp;-t&nbsp;demo&nbsp;.</p><p>Sending&nbsp;build&nbsp;context&nbsp;to&nbsp;Docker&nbsp;daemon&nbsp;&nbsp;33.28kB</p><p>Step&nbsp;1/2&nbsp;:&nbsp;FROM&nbsp;node:12-alpine</p><p>&nbsp;---&gt;&nbsp;18f4bc975732</p><p>Step&nbsp;2/2&nbsp;:&nbsp;RUN&nbsp;node&nbsp;-e&nbsp;\"Promise.reject(\'hello,&nbsp;world\')\"</p><p>&nbsp;---&gt;&nbsp;Running&nbsp;in&nbsp;79a6d53c5aa6</p><p>(node:1)&nbsp;UnhandledPromiseRejectionWarning:&nbsp;hello,&nbsp;world</p><p>(node:1)&nbsp;UnhandledPromiseRejectionWarning:&nbsp;Unhandled&nbsp;promise&nbsp;rejection.&nbsp;This&nbsp;error&nbsp;originated&nbsp;either&nbsp;by&nbsp;throwing&nbsp;inside&nbsp;of&nbsp;an&nbsp;async&nbsp;function&nbsp;without&nbsp;a&nbsp;catch&nbsp;block,&nbsp;or&nbsp;by&nbsp;rejecting&nbsp;a&nbsp;promise&nbsp;which&nbsp;was&nbsp;not&nbsp;handled&nbsp;with&nbsp;.catch().&nbsp;To&nbsp;terminate&nbsp;the&nbsp;node&nbsp;process&nbsp;on&nbsp;unhandled&nbsp;promise&nbsp;rejection,&nbsp;use&nbsp;the&nbsp;CLI&nbsp;flag&nbsp;`--unhandled-rejections=strict`&nbsp;(see&nbsp;https://nodejs.org/api/cli.html</p><p><i>#cli_unhandled_rejections_mode).&nbsp;(rejection&nbsp;id:&nbsp;1)</i></p><p>(node:1)&nbsp;[DEP0018]&nbsp;DeprecationWarning:&nbsp;Unhandled&nbsp;promise&nbsp;rejections&nbsp;are&nbsp;deprecated.&nbsp;In&nbsp;the&nbsp;future,&nbsp;promise&nbsp;rejections&nbsp;that&nbsp;are&nbsp;not&nbsp;handled&nbsp;will&nbsp;terminate&nbsp;the&nbsp;Node.js&nbsp;process&nbsp;with&nbsp;a&nbsp;non-zero&nbsp;exit&nbsp;code.</p><p>Removing&nbsp;intermediate&nbsp;container&nbsp;79a6d53c5aa6</p><p>&nbsp;---&gt;&nbsp;09f07eb993fe</p><p>Successfully&nbsp;built&nbsp;09f07eb993fe</p><p>Successfully&nbsp;tagged&nbsp;demo:latest</p><h2><strong>Promise.reject 脚本解决方案</strong></h2><p>能在编译时能发现的问题，绝不要放在运行时。所以，构建镜像或 CI 中需要执行 node 脚本时，对异常处理需要手动指定 process.exitCode = 1 来提前暴露问题</p><p>runScript().catch(()&nbsp;=&gt;&nbsp;{</p><p>&nbsp;&nbsp;process.exitCode&nbsp;=&nbsp;1</p><p>})</p><p>在构建镜像时，也有关于异常解决方案的建议：</p><blockquote><p><strong>❝</strong></p><p>(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)</p><p>❞</p></blockquote><p>根据提示，--unhandled-rejections=strict 将会把 Promise.reject 的退出码设置为 1，并在将来的 node 版本中修正 Promise 异常退出码。</p><p>$&nbsp;node&nbsp;--unhandled-rejections=strict&nbsp;error.js</p><p>--unhandled-rejections=strict 的配置对 node 有版本要求：</p><blockquote><p><strong>❝</strong></p><p>Added in: v12.0.0, v10.17.0</p><p>By default all unhandled rejections trigger a warning plus a deprecation warning for the very first unhandled rejection in case no unhandledRejection hook is used.</p><p>❞</p></blockquote><h2><strong>总结</strong></h2><ol><li>当进程结束的 exit code 为非 0 时，系统会认为该进程执行失败</li><li>通过 echo $? 可查看终端上一进程的 exit code</li><li>Node 中 Promise.reject 时 exit code 为 0</li><li>Node 中可以通过 process.exitCode = 1 显式设置 exit code</li><li>在 Node12+ 中可以通过 node --unhandled-rejections=strict error.js 执行脚本，视 Promise.reject 的 exit code 为 1</li></ol>', '/uploads/page/20200921/800963d0bdc547bee61cde217cef0abc.jpeg', 1, '[10, 11]', 35, '2020-09-21 17:58:27', 'now', 1, 237, 0, 0, 'now', 'now', 1, 1, '2020-09-01 18:52:27', '2020-09-21 11:09:28');
INSERT INTO `page` VALUES (9, 2, '两位“军工系”同日晋升！他成了全国最年轻省委书记', '据官网介绍，中国兵器工业集团有限公司，是我军机械化、信息化、智能化装备发展的骨干，是全军毁伤打击的核心支撑，是现代化新型陆军体系作战能力科研制造的主体，是国家“一带一路”建设和军民融合发展的主力。', '<p>原标题：两位“军工系”同日晋升！他成了全国最年轻省委书记</p><p>&nbsp;</p><p>&nbsp;来源：北京青年报</p><p>&nbsp;</p><p>&nbsp;撰文 | &nbsp;蔡迩一</p><p>&nbsp;</p><p>&nbsp;重磅！</p><p>&nbsp;</p><p>&nbsp;一天之内，辽宁、浙江两省有重磅人事调整：</p><p>&nbsp;</p><p>&nbsp;张国清任辽宁省委书记，陈求发不再担任辽宁省委书记</p><p>&nbsp;</p><p>&nbsp;袁家军任浙江省委书记，车俊不再担任浙江省委书记</p><p>&nbsp;</p><p>&nbsp;张国清和袁家军都是军工系统出身的专家型人才，张国清曾掌舵中国兵器工业集团公司，袁家军曾任航天科技集团副总经理。</p><p>&nbsp;</p><p>&nbsp;伴随着此番履新，“军工少帅”张国清成为目前全国最年轻的省级党委书记。</p><p>&nbsp;</p><p>&nbsp;“军工少帅”张国清</p><p>&nbsp;</p><p>&nbsp;张国清，男，汉族，1964年8月生，今年56岁，河南罗山人，1984年7月加入中国共产党，1985年9月参加工作，在职研究生学历，经济学博士，研究员级高级工程师。十九届中央委员。</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;政知君注意到，张国清长期在军工系统工作，是政坛中著名的军工少帅之一。</p><p>&nbsp;</p><p>&nbsp;2004年4月，40岁的张国清就成为中国兵器工业集团公司副总经理兼中国北方工业公司总裁，43岁出任中国兵器工业集团公司党组书记，晋升部级。</p><p>&nbsp;</p><p>&nbsp;据官网介绍，中国兵器工业集团有限公司，是我军机械化、信息化、智能化装备发展的骨干，是全军毁伤打击的核心支撑，是现代化新型陆军体系作战能力科研制造的主体，是国家“一带一路”建设和军民融合发展的主力。</p><p>&nbsp;</p><p>&nbsp;十八大后（2013年4月），张国清空降重庆，担任重庆市委副书记，2016年12月，张国清接棒“经济能手”黄奇帆，成为重庆新一任市长，出生于1964年的张国清，也成为当时最年轻的直辖市政府主官。</p><p>&nbsp;</p><p>&nbsp;政知君与张国清有过一面之缘。2016年10月，“中国共产党与世界对话会”在重庆举行，“走进重庆市委”是配套活动之一，让外国政党和专家代表第一次有机会走进省级党委。当时与代表进行交流，逐一解答大家问题的就是张国清。</p><p>&nbsp;</p><p>&nbsp;在提到重庆的产业结构和未来发展规划时，张国清的介绍中引入颇多数字，常常出现类似几分之几、百分之多少以及指数、比重等词汇。</p><p>&nbsp;</p><p>&nbsp;他回答问题时语速较快。参与交流的现场代表对张国清的计量经济学的专业背景很感兴趣，并询问这是否有利于把事情做实。</p><p>&nbsp;</p><p>&nbsp;市委大院举行的座谈会的最后，张国清还向政党代表推荐重庆的旅游，希望多在重庆待上几天，他说重庆的胜地颇多，按数量来看，一年半载可以不重样地参访。</p><p>&nbsp;</p><p>&nbsp;2017年10月，时任天津市长王东峰跨省到河北履新省委书记。之后，张国清北上，成为新一任的天津市市长，至今近3年。</p><p>&nbsp;</p><p>&nbsp;此前担任辽宁省委书记的是陈求发，巧合的是，陈求发也是军工系，早年曾在中国航天工业总公司工作。</p><p>&nbsp;</p><p>&nbsp;航天系袁家军</p><p>&nbsp;</p><p>&nbsp;据《中国经济周刊》2017年报道，中国建立了完整的国防工业体系，目前形成了十大军工巨头格局，他们分别是：</p><p>&nbsp;</p><p>&nbsp;中国航天科技集团、航天科工集团、航空工业集团、兵器工业集团、兵器装备集团、船舶工业集团、船舶重工集团、核工业集团、核工业建设集团、电子科技集团</p><p>&nbsp;</p><p>&nbsp;和张国清同日履新的袁家军，就出身于中国航天科技集团。</p><p>&nbsp;</p><p>&nbsp;袁家军，男，汉族，1962年9月生，今年58岁，吉林通化人。1987年7月参加工作，1992年11月加入中国共产党。研究生学历，工学博士，研究员。</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;袁家军毕业于北京航空学院飞机设计与应用力学系固体力学专业，后在航天工业部五院501部空间飞行器设计专业攻读硕士研究生。</p><p>&nbsp;</p><p>&nbsp;他从航天工业部501部开始职业生涯、一路升至中国航天科技集团副总经理。</p><p>&nbsp;</p><p>&nbsp;中国航天科技集团有限公司是我国航天科技工业的主导力量，主要从事运载火箭、各类卫星、载人飞船、货运飞船、深空探测器、空间站等宇航产品和战略、战术导弹武器系统的研究、设计、生产、试验和发射服务。</p><p>&nbsp;</p><p>&nbsp;多说几句。</p><p>&nbsp;</p><p>&nbsp;国防工业是国家整体工业体系的尖兵，航天更是尖兵中的尖兵。</p><p>&nbsp;</p><p>&nbsp;这几年来，中国航天科技集团公司连续走出了多位高官，除了袁家军外，现任黑龙江省委书记张庆伟、广东省省长马兴瑞、湖南省省长许达哲等也都是从这里走出去的。</p><p>&nbsp;</p><p>&nbsp;说回袁家军。</p><p>&nbsp;</p><p>&nbsp;袁家军拥有一系列显赫的专业头衔：中国载人航天工程飞船系统总指挥、中国探月工程副总指挥等。</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;2012年3月，袁家军被调往内地省份宁夏，任自治区党委常委、政府常务副主席、宁东能源化工基地管委会主任。2014年7月，袁家军又被调往沿海经济大省浙江。</p><p>&nbsp;</p><p>&nbsp;在浙江工作期间，他曾先后担任浙江常务副省长、政法委书记，2017年7月，袁家军履新浙江省省长，至今3年。</p><p>&nbsp;</p><p>&nbsp;此前担任浙江省委书记的是车俊，1955年7月出生的车俊，今年65岁。</p><p>&nbsp;</p><p>&nbsp;全国最年轻省级党委书记是张国清</p><p>&nbsp;</p><p>&nbsp;据政知君统计，目前，“60后”省级党委书记共5位，分别是：</p><p>&nbsp;</p><p>&nbsp;辽宁省委书记张国清（1964年8月）</p><p>&nbsp;</p><p>&nbsp;黑龙江省委书记张庆伟（1961年11月）</p><p>&nbsp;</p><p>&nbsp;浙江省委书记袁家军（1962年9月）</p><p>&nbsp;</p><p>&nbsp;重庆市委书记陈敏尔（1960年9月）</p><p>&nbsp;</p><p>&nbsp;陕西省委书记刘国中 （1962年7月）</p><p>&nbsp;</p><p>&nbsp;在今天之前，全国最年轻的省级党委书记是陕西的刘国中。</p><p>&nbsp;</p><p>&nbsp;刘国中是地方成长起来的官员，曾在黑龙江、四川、吉林、陕西等地工作，2018年1月任陕西省省长，今年7月，陕西省委原书记胡和平进京赴文旅部工作，刘国中从省长岗位晋升。</p><p>&nbsp;</p><p>&nbsp;不过，在这次调整后，辽宁新一任省委书记张国清，成为全国最年轻的省级党委书记。</p><p>&nbsp;</p><p>&nbsp;资料 | 新华社 &nbsp;人民网 等</p>', '/uploads/page/20200921/5a0c077f1daaf2c2ab70dac64d0dc194.jpg', 1, '[4, 10, 11]', 7, '2020-09-01 23:30:00', 'timing', 1, 552, 0, 0, 'now', 'now', 1, 5, '2020-09-01 23:18:51', '2020-09-21 10:00:01');
INSERT INTO `page` VALUES (11, 15, 'The SymfonyLive Paris conference is coming at the end of this month.', 'The conference tickets sale for SymfonyLive Paris 2020 is now sold out but we have a few seats left for the pre-conference workshops. Get trained on the latest about Symfony!', '<p>The SymfonyLive Paris conference is coming at the end of this month. While the conference is now sold out, there are still a few seats left available to attend the pre-conference workshops. As the conference is organized in French, the following blog post will be written in French.</p><p>Nous sommes impatients de vous retrouver à la fin du mois pour l’édition francophone du <a href=\"https://live.symfony.com/2020-paris/\">SymfonyLive Paris 2020</a>. Nous avons récemment annoncé que la <a href=\"https://symfony.com/blog/rendez-vous-at-the-end-of-this-month-for-symfonylive-paris-2020\">conférence est désormais sold out</a> due à la situation sanitaire actuelle, mais <strong>il est encore possible de vous inscrire pour participer aux formations pré-conférence du lundi 21 et mardi 22 septembre 2020</strong> et de participer également à la conférence du 23 et 24 septembre 2020.</p><p><strong>En tant qu\'organisme de formations officiel, votre formation peut être prise en charge par votre OPCA</strong>. <a href=\"https://symfony.com/blog/symfony-sas-is-now-an-official-training-center-in-france\">Retrouvez tous les détails concernant la prise en charge de votre formation</a> et <a href=\"https://symfony.com/support?product=SFC\">contactez-nous pour préparer votre inscription</a> !</p><p>Il nous reste quelques places pour participer aux formations, nous proposons deux formations de 2 journées consécutives et une formation combo composée de 2 journées de formations individuelles. Pour rappel, voici les <a href=\"https://live.symfony.com/2020-paris/workshop\">formations disponibles</a> :</p><ul><li><strong>Symfony 5: the fast track par Nicolas Grekas - Core-team Symfony</strong> (2 jours). Cette formation est issue du livre \"Symfony 5: The Fast Track\" de Fabien Potencier. Dispensée sur deux jours consécutifs, elle vous apprendra à construire une application Symfony de A à Z en utilisant les nouvelles pratiques et les nouveaux composants disponibles depuis peu. Nous construirons une application dotée de toute l\'infrastructure des apps modernes : base de données, serveur de cache applicatif et HTTP, bus de messages pour traitements en tâche de fond, API et SPA, etc. Pour se rapprocher d\'un projet réel, le développement s\'effectuera sur un double environnement prod/dev basés sur SymfonyCloud/Docker respectivement. Au menu : Flex, Mailer, Notifier, Workflow, Messenger, API Platform, HttpClient, String, Webpack Encore, etc.</li><li><strong>Maîtriser la POO &amp; les Design Patterns par Titouan Galopin - SymfonyInsight lead</strong> (2 jours). La Programmation Orientée Object (POO) va au-delà de la conception de classes et d\'interfaces. Elle inclut une grande variété de concepts tels que les objets, les entités, les \"value objects\", les services, les modèles de conception, les principes SOLID, la calisthenie, le couplage, etc. Cet atelier vous aidera à mieux comprendre tous ces concepts pour écrire un code orienté objet plus maintenable, plus robuste et plus testable. Vous découvrirez également les techniques permettant de réduire la complexité de votre code et de rendre vos classes plus spécifiques et donc plus simples. Vous apprendrez aussi à reconnaître et à exploiter la puissance des modèles de conception (fabrique, adaptateur, composite, décorateur, médiateur, stratégie, etc.).</li><li><strong>Développement d\'API avec API Platform organisée le lundi 21 septembre par Kévin Dunglas, créateur d\'API Platform</strong>. API Plaftorm est devenu un cadre très populaire pour construire des projets Web avancés et modernes pilotés par API. Après une vue d\'ensemble des modèles et formats modernes de l\'API (REST, Swagger, Hypermedia, HATEOAS, JSON-LD, Hydra, Schema.org, GraphQL...), nous apprendrons comment utiliser et étendre les fonctionnalités les plus populaires du composant : documentation Swagger, pagination, validation, tri, filtrage, authentification, autorisation, négociation de contenu, génération de modèles de données à l\'aide du vocabulaire Schema.org. Enfin, nous découvrirons à quel point il est facile d\'utiliser la boîte à outils côté client (JavaScript).</li><li><strong>Traitements asynchrones avec Symfony Messenger organisée le mardi 22 septembre par Samuel Rozé, créateur du composant</strong>. Le composant Messenger de Symfony introduit la notion de “message bus” et de traitement asynchrone de ces messages, via un queue comme RabbitMq, Redis ou bien même via une simple base de données. Dans ce workshop découpé en 8 grand thèmes, vous allez d\'abord découvrir (1) comment utiliser Messenger pour découpler vos applications, (2) le système de routage vers des “transports” asynchrones et (3) les notions de “middleware” et de “stamps”, qui vous permettront de comprendre comment fonctionne le coeur du composant et de le personnaliser a vos souhaits. Nous verrons ensuite en détails (4) comment configurer les transports, (5) le système de sérialisation des messages, (6) la gestion des erreurs, (7) les événements du worker Messenger et (8) comment écrire vos propres transports.</li></ul><p>L\'inscription aux formations inclut les 2 journées de formations, il n\'est pas possible de s\'inscrire à une journée de formation seulement. En vous inscrivant aux formations, vous serez également inscrit à la conférence ! Les formations auront lieu à Clichy et la conférence à la Cité Internationale Universitaire de Paris.</p><p><strong>Mettez à profit votre compte CPF pour participer à nos formations</strong>, <a href=\"https://symfony.com/support?product=SFC\">faites vite votre demande d\'inscription</a> !</p>', '/uploads/page/20200921/253e709a4804f763a3b75882483077e6.jpg', 1, '[1, 2]', 47, '2020-09-09 15:00:00', 'timing', 1, 76, 0, 0, 'symfony,SymfonyLive,2020', 'The conference tickets sale for SymfonyLive Paris 2020 is now sold out but we have a few seats left for the pre-conference workshops. Get trained on the latest about Symfony!', 1, 1, '2020-09-05 16:20:09', '2020-09-21 17:13:18');
INSERT INTO `page` VALUES (12, 2, 'New in SymfonyInsight: Microsoft Teams analysis results notifications', 'One of the main goal of SymfonyInsight is to help you maintain high quality in your project over long periods of time. To do so, integrating the information SymfonyInsight gives you in your processes is key.', '<p>One of the main goal of SymfonyInsight is to help you maintain high quality in your project over long periods of time. To do so, integrating the information SymfonyInsight gives you in your processes is key.</p><p>SymfonyInsight already integrates natively with GitHub and Slack, and has the ability to be used in Bitbucket and GitLab as well using the SDK. You can even use a custom webhook to create a completely custom integration with any tool you would like.</p><p>Starting from today, you can also use Microsoft Teams natively on SymfonyInsight by using a few lines of configuration:</p><figure class=\"table\"><table><tbody><tr><td>1 2 3 4 5 6 7 8 9</td><td>notifications: &nbsp; &nbsp;- type: teams &nbsp; &nbsp; &nbsp;<i># The Teams WebHook URL (see the documentation for more details)</i> &nbsp; &nbsp; &nbsp;url: https://outlook.office.com/webhook/XXXXXXXXXX@XXXXXXXXX/IncomingWebhook/XXXXXXXXXXXXXX &nbsp; &nbsp; &nbsp;<i># On which event SymfonyInsight should post notifications</i> &nbsp; &nbsp; &nbsp;on_success: true &nbsp;<i># Notify when an analysis succeeded</i> &nbsp; &nbsp; &nbsp;on_failure: true &nbsp;<i># Notify when an analysis failed or errored</i></td></tr></tbody></table></figure><p>You can read the <a href=\"https://insight.symfony.com/docs/notifications/receive-teams-notifications.html\">dedicated documentation</a> to learn more about this new feature.</p><p>And as always, if you have any issue, feel free to contact us at the support!</p><p>Enjoy!</p><p><strong>Help the Symfony project!</strong></p><p><br>As with any Open-Source project, <a href=\"https://symfony.com/en/doc/current/contributing.html\">contributing</a> code or documentation is the most common way to help, but we also have a wide range of <a href=\"https://symfony.com/sponsor\">sponsoring opportunities</a>.</p>', '/uploads/page/20200911/4cef3fcffd4775c8a4a589b79e11365e.jpg', 1, '[1, 2]', 6, '2020-09-21 13:05:12', 'now', 1, 72, 1, 0, NULL, NULL, 1, 1, '2020-09-11 17:56:20', '2020-09-21 17:13:48');
INSERT INTO `page` VALUES (13, 2, 'Some seats left for the pre-conference workshops at SymfonyLive Paris 2020', 'The SymfonyLive Paris conference is coming at the end of this month. While the conference is now sold out, there are still a few seats left available to attend the pre-conference workshops. As the conference is organized in French, the following blog post will be written in French.', '<p>The SymfonyLive Paris conference is coming at the end of this month. While the conference is now sold out, there are still a few seats left available to attend the pre-conference workshops. As the conference is organized in French, the following blog post will be written in French.</p><p>Nous sommes impatients de vous retrouver à la fin du mois pour l’édition francophone du <a href=\"https://live.symfony.com/2020-paris/\">SymfonyLive Paris 2020</a>. Nous avons récemment annoncé que la <a href=\"https://symfony.com/blog/rendez-vous-at-the-end-of-this-month-for-symfonylive-paris-2020\">conférence est désormais sold out</a> due à la situation sanitaire actuelle, mais <strong>il est encore possible de vous inscrire pour participer aux formations pré-conférence du lundi 21 et mardi 22 septembre 2020</strong> et de participer également à la conférence du 23 et 24 septembre 2020.</p><p><strong>En tant qu\'organisme de formations officiel, votre formation peut être prise en charge par votre OPCA</strong>. <a href=\"https://symfony.com/blog/symfony-sas-is-now-an-official-training-center-in-france\">Retrouvez tous les détails concernant la prise en charge de votre formation</a> et <a href=\"https://symfony.com/support?product=SFC\">contactez-nous pour préparer votre inscription</a> !</p><p>Il nous reste quelques places pour participer aux formations, nous proposons deux formations de 2 journées consécutives et une formation combo composée de 2 journées de formations individuelles. Pour rappel, voici les <a href=\"https://live.symfony.com/2020-paris/workshop\">formations disponibles</a> :</p><ul><li><strong>Symfony 5: the fast track par Nicolas Grekas - Core-team Symfony</strong> (2 jours). Cette formation est issue du livre \"Symfony 5: The Fast Track\" de Fabien Potencier. Dispensée sur deux jours consécutifs, elle vous apprendra à construire une application Symfony de A à Z en utilisant les nouvelles pratiques et les nouveaux composants disponibles depuis peu. Nous construirons une application dotée de toute l\'infrastructure des apps modernes : base de données, serveur de cache applicatif et HTTP, bus de messages pour traitements en tâche de fond, API et SPA, etc. Pour se rapprocher d\'un projet réel, le développement s\'effectuera sur un double environnement prod/dev basés sur SymfonyCloud/Docker respectivement. Au menu : Flex, Mailer, Notifier, Workflow, Messenger, API Platform, HttpClient, String, Webpack Encore, etc.</li><li><strong>Maîtriser la POO &amp; les Design Patterns par Titouan Galopin - SymfonyInsight lead</strong> (2 jours). La Programmation Orientée Object (POO) va au-delà de la conception de classes et d\'interfaces. Elle inclut une grande variété de concepts tels que les objets, les entités, les \"value objects\", les services, les modèles de conception, les principes SOLID, la calisthenie, le couplage, etc. Cet atelier vous aidera à mieux comprendre tous ces concepts pour écrire un code orienté objet plus maintenable, plus robuste et plus testable. Vous découvrirez également les techniques permettant de réduire la complexité de votre code et de rendre vos classes plus spécifiques et donc plus simples. Vous apprendrez aussi à reconnaître et à exploiter la puissance des modèles de conception (fabrique, adaptateur, composite, décorateur, médiateur, stratégie, etc.).</li><li><strong>Développement d\'API avec API Platform organisée le lundi 21 septembre par Kévin Dunglas, créateur d\'API Platform</strong>. API Plaftorm est devenu un cadre très populaire pour construire des projets Web avancés et modernes pilotés par API. Après une vue d\'ensemble des modèles et formats modernes de l\'API (REST, Swagger, Hypermedia, HATEOAS, JSON-LD, Hydra, Schema.org, GraphQL...), nous apprendrons comment utiliser et étendre les fonctionnalités les plus populaires du composant : documentation Swagger, pagination, validation, tri, filtrage, authentification, autorisation, négociation de contenu, génération de modèles de données à l\'aide du vocabulaire Schema.org. Enfin, nous découvrirons à quel point il est facile d\'utiliser la boîte à outils côté client (JavaScript).</li><li><strong>Traitements asynchrones avec Symfony Messenger organisée le mardi 22 septembre par Samuel Rozé, créateur du composant</strong>. Le composant Messenger de Symfony introduit la notion de “message bus” et de traitement asynchrone de ces messages, via un queue comme RabbitMq, Redis ou bien même via une simple base de données. Dans ce workshop découpé en 8 grand thèmes, vous allez d\'abord découvrir (1) comment utiliser Messenger pour découpler vos applications, (2) le système de routage vers des “transports” asynchrones et (3) les notions de “middleware” et de “stamps”, qui vous permettront de comprendre comment fonctionne le coeur du composant et de le personnaliser a vos souhaits. Nous verrons ensuite en détails (4) comment configurer les transports, (5) le système de sérialisation des messages, (6) la gestion des erreurs, (7) les événements du worker Messenger et (8) comment écrire vos propres transports.</li></ul><p>L\'inscription aux formations inclut les 2 journées de formations, il n\'est pas possible de s\'inscrire à une journée de formation seulement. En vous inscrivant aux formations, vous serez également inscrit à la conférence ! Les formations auront lieu à Clichy et la conférence à la Cité Internationale Universitaire de Paris.</p><p><strong>Mettez à profit votre compte CPF pour participer à nos formations</strong>, <a href=\"https://symfony.com/support?product=SFC\">faites vite votre demande d\'inscription</a> !</p>', '/uploads/page/20200911/3ba9fd5669ad61460910259e2066781e.jpg', 1, '[1, 2]', 36, '2020-09-11 18:06:47', 'now', 1, 57, 0, 0, NULL, NULL, 1, 1, '2020-09-11 17:58:57', '2020-09-21 17:13:53');
INSERT INTO `page` VALUES (14, 2, 'Rendez-vous at the end of this month for SymfonyLive Paris 2020', 'The French SymfonyLive conference will take place on September 23-24 2020. Initially scheduled on March 26-27 2020, the event has been postponed to September due to the Covid-19 situation and the global lockdown. We’re pleased to welcome all the attendees of the conference thanks to all the security measures we’ve taken to organize a safe event.', '<p>The French SymfonyLive conference will take place on September 23-24 2020. Initially scheduled on March 26-27 2020, the event has been postponed to September due to the Covid-19 situation and the global lockdown. We’re pleased to welcome all the attendees of the conference thanks to all the security measures we’ve taken to organize a safe event. This year, the event will welcome a maximum of 500 attendees to organize an event of quality with a maximum of safety. As the conference is organized in French, the following blog post will be written in French.</p><p>Nous sommes ravis de vous <strong>donner rendez-vous au </strong><a href=\"https://live.symfony.com/2020-paris/\"><strong>SymfonyLive Paris 2020</strong></a><strong> les 23 et 24 septembre</strong>. Initialement programmée les 26 et 27 mars 2020, la conférence a été reportée suite à la crise sanitaire du Covid-19 et au confinement national qui a été instauré. <strong>Votre inscription au SymfonyLive Paris 2020 a été automatiquement reportée à la conférence de septembre</strong>.</p><p>Nous vous confirmons (sauf décision gouvernementale de dernière minute) que <strong>la conférence est bien maintenue et que nous avons pris toutes les dispositions nécessaires</strong> pour son bon déroulement en adéquation avec les normes sanitaires actuelles. Nous avons longuement hésité mais nous avons pris la décision de maintenir l’événement. En effet, concernant la logistique tout était prêt avant le confinement, il ne nous manquait que l\'autorisation du gouvernement permettant l\'organisation des événements qui est entré en vigueur fin août. Il nous semble important de permettre à la communauté de se retrouver puisque toutes les conditions nous permettent d’organiser sereinement la conférence. Nous avons, par contre, pris la décision de <strong>limiter la capacité d’accueil de la conférence à 500 participants</strong> pour qu’elle ait lieu dans les meilleures conditions possibles. Voici ci-dessous, en toute transparence, la liste des mesures que nous prenons pour garantir la sécurité de tous durant l’événement.</p><p>Tout d’abord, <strong>le port du masque sera obligatoire</strong> durant tout l’événement. Chaque participant est invité à se munir d’un masque pour accéder à la Cité Internationale de Paris et à la conférence, sans quoi l’accès à l’événement vous sera refusé. Le port du masque étant obligatoire dans Paris, il en est de même pour tout l\'événement. Ensuite, <strong>du gel hydroalcoolique sera à disposition</strong> dans toutes les salles de l’événement pour que chacun puisse se désinfecter les mains très régulièrement. Les règles de distanciation sociale seront respectées puisqu’un <strong>siège sur deux sera disponible dans l’amphithéâtre</strong> pour vous asseoir durant les conférences. Des sièges supplémentaires seront mis en place dans les galeries de l’amphithéâtre afin d’accueillir tous les participants dans la même salle. Avec les normes de distanciation sociale, nous avons dû repenser intégralement la disposition de l’amphithéâtre et nous ne pouvons malheureusement pas accueillir autant de participants que lors des éditions précédentes. <strong>C’est pourquoi la conférence est désormais Sold Out</strong>. Un sens de circulation sera mis en place pour respecter les distances de sécurité et fluidifier les entrées et sorties. En ce qui concerne les pauses cafés et les pauses déjeuners, <strong>il n’y aura pas de buffet mais des portions individuelles et des lunch box</strong>. Les repas devant être obligatoirement pris assis, nous vous demanderons de vous rendre soit dans la salle de conférence soit dans les salles de déjeuner pour manger. Il ne sera pas possible de manger debout à aucun moment. Par conséquent, nous avons décidé d’annuler le petit-déjeuner de bienvenue et l’apéritif communautaire qui ne nous semblaient pas possible de maintenir dans de bonnes conditions avec le contexte actuel. Enfin, le <strong>vestiaire sera uniquement ouvert pour y déposer vos casques</strong> si vous venez en moto ou scooter. Le vestiaire ne sera pas disponible pour y déposer vos vêtements ou sacs.</p><p>Une <strong>équipe de nettoyage interviendra régulièrement</strong> pour désinfecter les salles, les fenêtres seront ouvertes à la fin de chaque conférence et durant les pauses. Les micro des speakers seront équipés de housse de protection à usage unique. Le pupitre sera nettoyé après chaque conférence.</p><p>A partir de cette année, <strong>il n’y aura plus de retrait des badges puisqu’ils seront téléchargeables en PDF depuis le site </strong><a href=\"https://live.symfony.com/2020-paris/\"><strong>SymfonyLive Paris 2020</strong></a>. Ils seront disponibles en téléchargement une semaine avant l’événement, vous n’aurez plus qu’à les imprimer pour accéder à la conférence. Des porte-badges et des lanyards seront à votre disposition pour que vous puissiez porter votre badge et qu’il soit visible en toutes circonstances. Les stands de nos sponsors seront accessibles mais nous vous demanderons de respecter les distances de sécurité et de vous y rendre par petits groupes. Afin de fluidifier les arrivées à la conférence, <strong>les portes de l’événement seront ouvertes dès 8h, la conférence commence à 9h</strong>. <a href=\"https://live.symfony.com/2020-paris/schedule\">Découvrez le programme complet de l\'événement</a>.</p><p>Nos équipes seront présentes pour vérifier que tout le monde porte son masque et que les règles de distanciation sont bien respectées. Afin d’offrir un événement de qualité à tous dans un cadre convivial malgré la crise sanitaire que nous traversons, nous vous invitons à respecter toutes ces mesures. Nous avons décidé de maintenir la conférence car les événements physiques restent malgré tout une expérience extraordinaire pleine de rencontres, de partage et parce qu’après le confinement que nous avons tous vécu, il est important de se retrouver en dehors du virtuel ! Nous avons pris toutes les mesures pour ne prendre aucun risque pendant la conférence mais nous avons besoin de vous pour faire de cet événement une réussite. Nous avons hâte de vous retrouver ! Si vous avez la moindre question, n’hésitez pas à <a href=\"https://symfony.com/support?product=SFC\">nous contacter via le support</a>.</p><p>A très vite !</p>', '/uploads/page/20200911/251c637a3cc1c98a91434ed723a3bb10.jpg', 1, '[1, 2]', 65, '2020-09-21 13:00:56', 'now', 1, 74, 0, 0, NULL, NULL, 1, 1, '2020-09-11 18:05:08', '2020-09-21 16:54:20');
INSERT INTO `page` VALUES (15, 2, 'SymfonyLive Paris 2020: regular registration ends on March 2nd', 'Only a few days left to register at the regular fee, price changes on March 2nd 2020. As the conference is organized in French, the following blog post will be written in French.', '<p>Only a few days left to register at the regular fee, price changes on March 2nd 2020. As the conference is organized in French, the following blog post will be written in French.</p>\r\n<p>La conf&eacute;rence <a href=\"https://paris2020.live.symfony.com/\">SymfonyLive Paris 2020</a> c&rsquo;est dans moins d&rsquo;un mois ! Nous avons annonc&eacute; la semaine derni&egrave;re tout le programme de l&rsquo;&eacute;v&eacute;nement, si vous avez manqu&eacute; nos annonces, retrouvez l&rsquo;annonce de la <a href=\"https://symfony.com/blog/symfonylive-paris-2020-first-part-of-the-conference-schedule-is-online\">1&egrave;re partie du programme</a> et celle sur la <a href=\"https://symfony.com/blog/symfonylive-paris-2020-second-part-of-the-conference-schedule-is-online\">2e partie du programme</a>. L\'inscription au tarif normal est disponible pour quelques jours encore jusqu\'au 2 mars (inclus), profitez-en !</p>\r\n<p>Nous sommes tr&egrave;s heureux de vous retrouver pour 4 jours d\'&eacute;v&eacute;nement. Les <strong>24 et 25 mars</strong>, on se retrouve pour <strong>2 journ&eacute;es de formation pr&eacute;-conf&eacute;rence</strong> avec plusieurs formations propos&eacute;es en amont du SymfonyLive Paris :</p>\r\n<ul>\r\n<li><strong>Symfony 5: the fast track par Nicolas Grekas</strong> - Core-team Symfony (2 jours)</li>\r\n<li><strong>Ma&icirc;triser la POO &amp; les Design Patterns par Titouan Galopin</strong> - SymfonyInsight lead (2 jours)</li>\r\n<li><strong>Ma&icirc;triser Elasticsearch par Damien Alexandre</strong> - Expert Web, Symfony et Elasticsearch chez JoliCode (2 jours)</li>\r\n<li><strong>D&eacute;veloppement d\'API avec API Platform par K&eacute;vin Dunglas</strong>, cr&eacute;ateur d\'API Platform (1 jour le mardi 24 mars)</li>\r\n<li><strong>Traitements asynchrones avec Symfony Messenger par Samuel Roz&eacute;</strong>, cr&eacute;ateur du composant (1 jour le mercredi 25 mars)</li>\r\n<li><strong>Analyser les performances des applications Symfony par J&eacute;r&ocirc;me Vieilledent</strong> - Developer Advocate Blackfire (1 jour le mercredi 25 mars)</li>\r\n</ul>\r\n<p>D&eacute;couvrez le <a href=\"https://paris2020.live.symfony.com/workshop\">programme de chaque formation</a> et r&eacute;servez vite votre billet combo, le nombre de places aux formations est limit&eacute; !</p>\r\n<p>Les <strong>26 et 27 mars</strong>, on se retrouve pour <strong>2 journ&eacute;es de conf&eacute;rence</strong> &agrave; la Cit&eacute; Internationale Universitaire de Paris. Le <a href=\"https://paris2020.live.symfony.com/speakers\">programme complet de l\'&eacute;v&eacute;nement</a> est en ligne, d&eacute;couvrez un aper&ccedil;u des speakers et leurs sujets :</p>\r\n<ul>\r\n<li><strong>Romaric Drigon</strong>, Software Engineer et Symfony-addict depuis la version beta 2.0, pr&eacute;sentera \" <a href=\"https://paris2020.live.symfony.com/speakers#session-3320\">Un service, k&eacute;sako ? Conseils pour mieux utiliser l\'injection de d&eacute;pendance</a> \"</li>\r\n<li><strong>Valentine Boineau</strong>, SymfonyInsight Developer, parlera de \" <a href=\"https://paris2020.live.symfony.com/speakers#session-3316\">La compilation JIT, le fil rouge vers PHP 8</a> \"</li>\r\n<li><strong>Nicolas Grekas</strong>, membre de la Core Team Symfony et Ing&eacute;nieur principal chez Symfony SAS, vous expliquera comment \" <a href=\"https://paris2020.live.symfony.com/speakers#session-3217\">Mettre la cryptographie au service de vos apps Symfony</a> \".</li>\r\n<li><strong>Samuel Roze</strong>, VP of Engineering chez Birdie, membre de la Core Team Symfony et cr&eacute;ateur du composant Messenger, expliquera le \" <a href=\"https://paris2020.live.symfony.com/speakers#session-3253\">Stream processing: un autre type d&rsquo;architecture</a> \"</li>\r\n<li><strong>K&eacute;vin Dunglas</strong>, membre de la Core Team Symfony, fondateur de Les-Tilleuls.coop et cr&eacute;ateur d\'API Platform, pr&eacute;sentera \" <a href=\"https://paris2020.live.symfony.com/speakers#session-3203\">HYPErmedia : tirer parti d\'HTTP/2 pour cr&eacute;er des API mieux con&ccedil;ues, et plus rapides</a> \"</li>\r\n</ul>\r\n<p><a href=\"https://paris2020.live.symfony.com/registration/\">Inscrivez-vous</a> d&egrave;s maintenant au SymfonyLive Paris 2020, le <strong>prix change lundi 2 mars &agrave; minuit (heure de Paris)</strong>, n\'attendez plus pour prendre vos places !</p>', '/uploads/page/20200911/dfb914f17ed7454fbd7896e4bcd53e72.jpg', 1, '[1, 2]', 79, '2020-11-01 08:52:25', 'now', 1, 46, 0, 0, NULL, NULL, 1, 1, '2020-09-11 18:06:22', '2020-11-01 08:52:25');
INSERT INTO `page` VALUES (16, 2, 'SymfonyConnect adds new badges for Sylius and API Platform', 'SymfonyConnect also defines tens of badges to recognize the activity of Symfony developers in the community (e.g. attending an event, contributing code or docs to some repository, passing the Symfony Certification exam, etc.)', '<p><a href=\"https://connect.symfony.com/\">SymfonyConnect</a> is the social network for Symfony developers and it\'s used to authenticate in <a href=\"https://symfonycasts.com/\">SymfonyCasts</a>, <a href=\"https://live.symfony.com/\">Symfony Conferences</a> and many other Symfony services.</p><p>SymfonyConnect also defines <a href=\"https://connect.symfony.com/badges\">tens of badges</a> to recognize the activity of Symfony developers in the community (e.g. attending an event, contributing code or docs to some repository, passing the <a href=\"https://certification.symfony.com/\">Symfony Certification</a> exam, etc.)</p><p>We\'ve already awarded hundreds of thousands of badges to our amazing community and we\'re always thinking about adding new badges. That\'s why a few days ago we introduced two new badges related to code contributions:</p><ul><li><a href=\"https://connect.symfony.com/badge/147/sylius-code-contributor\">Sylius Code Contributor</a>, which is awarded to people who have contributed code to any of the repositories of the <a href=\"https://sylius.com/\">Sylius project</a>, an Open Source eCommerce Platform developed with Symfony;</li><li><a href=\"https://connect.symfony.com/badge/148/api-platform-code-contributor\">API Platform Code Contributor</a>, which is awarded to people who have contributed code to any of the repositories of the <a href=\"https://api-platform.com/\">API Platform project</a>, a REST and GraphQL framework on top of Symfony and React.</li></ul><p>We\'ve also created a new <a href=\"https://connect.symfony.com/badge/149/symfony-5-book-backer\">Symfony 5 Book Backer</a> badge to thank all of you who contributed to the original Kickstarter campaign for the <a href=\"https://symfony.com/blog/symfony-5-the-fast-track-a-new-symfony-book\">Symfony 5 book</a>. This is how these new badges look:</p><figure class=\"image\"><img src=\"https://symfony.com/uploads/assets/blog/symfony-connect-badges-sylius-api-platform.png\" alt=\"SymfonyConnect badges for Sylius, API Platform and the Symfony 5 book\"></figure><p>Hundreds of developers have been awarded these badges already. If you don\'t have a SymfonyConnect account, <a href=\"https://connect.symfony.com/login\">sign up for free in 1 minute</a> and start collecting badges.</p>', '/uploads/page/20200911/5625200f71a4db792ede9f32eb60488e.jpg', 1, '[1, 2]', 8, '2020-09-21 13:00:21', 'now', 1, 235, 0, 0, NULL, NULL, 1, 1, '2020-09-11 18:07:59', '2020-10-24 21:49:47');
INSERT INTO `page` VALUES (17, 4, 'Linux 内核对 Rust 的支持有新进展，双方进行深入探讨', '在八月底举办的 2020 Linux Plumbers 大会上，关于 Linux 内核上游对 Rust 的开放程度成为了最热门的讨论话题。Rust 语言团队的联合负责人 Thomas 和 Gaynor，以及 Linux 内核开发者 Josh Triplett 等人参与了这场讨论，并向大家展示了截至目前的一些研究成果、想法，还有遇到的问题。', '<p>从去年九月，Linux 内核维护者 Greg 表示<a href=\"http://www.oschina.net/news/109553/rust-for-linux-kernel\">愿意接受用 Rust 开发 Linux 驱动</a>，到今年七月，Linus Torvalds 回应称可以<a href=\"https://www.oschina.net/news/117139/linus-linux-rust-support-remark\">默认启用 Rust 支持</a>，Linux 开发者并非只是说说而已。</p><p>在八月底举办的&nbsp;2020 Linux Plumbers 大会上，关于 Linux 内核上游对 Rust 的开放程度成为了最热门的讨论话题。Rust 语言团队的联合负责人&nbsp;Thomas 和 Gaynor，以及 Linux 内核开发者&nbsp;Josh Triplett 等人参与了<a href=\"https://lwn.net/SubscriberLink/829858/281103f9c6fd0dc2/\">这场讨论</a>，并向大家展示了截至目前的一些研究成果、想法，还有遇到的问题。</p><p>他们强调，并不打算将已有的内核改写成 Rust，而只专注于可以用 Rust 编写的新代码。具体来讲，与会者集中讨论了 Linux 内核对&nbsp;Rust 的支持可能涉及到的三个方面：内核中现有的 API、架构支持，和 ABI 与内核的兼容性问题。</p><figure class=\"image\"><img src=\"https://static.oschina.net/uploads/space/2020/0903/183215_l4ZP_4105562.png\" alt=\"\"></figure><h4><strong>绑定到现有的 C API</strong></h4><p>目前来看，Rust 能够生成可以链接到内核的代码还不够。它还需要一种方法来访问 Linux 内核中使用的大量 API，这些 API 目前都在 C 头文件中定义。</p><p>Linux 内核开发者指出，Rust 与 C 具有良好的互操作性；此外，<a href=\"https://github.com/rust-lang/rust-bindgen\">bindgen</a> 工具能够解析 C 头文件以生成适当的 Rust 声明，因此 Rust 不需要从 C 复制重复的定义，这也提供了一种跨语言类型检查的措施。</p><p>从表面上看，这些特性使 Rust 具备了与现有 C API 集成的良好条件，但实际上实施起来还存在一些挑战。例如，Linux 大量使用了预处理器宏和内联函数，bindgen 和 Rust 的外函数接口不容易支持它们。</p><p>有关 API 绑定的第二个问题是：需要手动封装多少 C API 才能呈现惯用的 Rust 接口？</p><p>Thomas 和 Gaynor 展示了一个&nbsp;<a href=\"https://github.com/fishinabarrel/linux-kernel-module-rust/\">linux-kernel-module-rust</a>&nbsp;项目，可在其中看到内核模式的 Rust 代码示例。在这个项目中，指向用户空间的指针被封装到 UserSlicePtr 类型中。这样的封装生成的代码对现有 Rust 开发者而言更加熟悉，并使 Rust 的类型系统和借用检查器提供最大程度的安全性。但是，必须针对每个 API 进行设计和开发，用 C 和 Rust 编写的模块也会创建不同的 API。这无疑加重了工作的繁琐度。</p><p>John Baublitz 也给出了一个<a href=\"https://github.com/jbaublitz/knock-out\">演示模块</a>，它更直接地绑定了内核的用户访问功能，绑定多由 bindgen 自动生成。然而，Rust 开发者对这些代码可能会不太习惯，并且这种方式可能需要放弃 Rust 的许多安全保证。</p><p>最后，会议达成了共识：对于某些最常见和关键的 API，编写 Rust 封装器是有意义的，但是手动封装每个内核 API 不可行。Thomas 还提到<a href=\"https://www.oschina.net/news/118148/chrome-rust-and-c-interoperability\">谷歌正致力于自动生成 C++ 代码的惯用绑定</a>，并考虑内核是否可以做类似的事情。</p><h4><strong>架构支持</strong></h4><p>对架构的支持是讨论的另一个重点。与会者表示，在 Rust 中实现 Linux 驱动是可以接受的，但无论如何不能把它放在更晦涩难懂的架构上。</p><p>在这方面，现阶段唯一成熟的 Rust 实现是 <a href=\"https://doc.rust-lang.org/rustc/what-is-rustc.html\">rustc</a> 编译器，该编译器通过 LLVM 发出代码。Linux 内核支持多种架构，其中一些没有可用的 LLVM 后端，另一些存在 LLVM 后端，却尚不受&nbsp;rustc 支持。</p><p>Triplett 认为，先将&nbsp;Rust 添加到 Linux 内核中，反过来会有助于增加对更多架构的 Rust 支持。就像 Rust 软件被引入&nbsp;Debian 后，吸引了更多不同架构的爱好者协助改进 Rust 支持一样，他寄希望于为 Linux 内核添加 Rust 支持也获得类似的效果。</p><h4><strong>ABI 与内核的兼容性</strong></h4><p>Gaynor 问到了有关 ABI 兼容性的建议。当前 Rust 是通过 LLVM 编译的，而 Linux 内核通常使用 GCC 构建，因此将 Rust 代码链接到内核可能意味着混合 GCC 和 LLVM 发出的代码。</p><p>参与讨论者担心 LLVM 与 GCC 可能会有 ABI 兼容的问题，于是提出一个设想，即 Linux 内核社区是否可以将 Rust 支持仅限于使用 Clang 构建的内核，以确保兼容性。</p><p>Linux 内核维护者 Greg 指出，当前的内核规则是，仅当内核中的所有目标文件使用相同的编译器并使用相同的标志构建时，才能保证兼容性。不过，他仍然对将 LLVM 构建的 Rust 对象链接到 GCC 构建的内核表示满意，因为只要配置适当，并通过测试即可。他认为不需要任何预先的限制，直到真正有实际问题产生。</p><p>另一位内核开发者&nbsp;Triplett 也强调，GCC 和 Rust 之间的调用是常规且普遍的，不必担心兼容性。因此目前看来，二者的兼容性问题目前不会成为将 Rust 引入 Linux 内核的阻碍。</p><p>这场会议上的讨论大致到此，暂时没有后续消息。随着越来越多的人对此抱有期待和热情，正如 <a href=\"https://lwn.net/SubscriberLink/829858/281103f9c6fd0dc2/\">LWN.net</a>&nbsp;所说，或许待一个具体的 Rust 内核驱动用例出现时，所有的争议和决策都将变得更加清晰。</p>', '/uploads/page/20200911/3097b265861fe8a8e03c6b9b3636c483.jpg', 1, '[11]', 3, '2020-09-11 18:11:06', 'now', 1, 77, 0, 0, NULL, NULL, 1, 1, '2020-09-11 18:11:06', '2020-09-21 16:54:50');
INSERT INTO `page` VALUES (18, 1, '华为鸿蒙 HarmonyOS 正式开源，进入开放原子开源基金会', '开源的鸿蒙项目名为 OpenHarmony。OpenHarmony 定位是一款面向全场景的开源分布式操作系统。根据介绍，OpenHarmony 在传统单设备系统能力的基础上，创造性地提出了基于同一套系统能力适配多种终端形态的理念，支持多种终端设备上运行，第一个版本支持 128K-128M 设备上运行。', '<p>9 月 10 日，华为在 HDC 2020 大会上宣布正式开源鸿蒙操作系统（HarmonyOS），源码地址：<a href=\"https://openharmony.gitee.com/\">https://openharmony.gitee.com</a>。</p><figure class=\"image\"><img src=\"https://static.oschina.net/uploads/space/2020/0910/152732_anBI_3820517.jpeg\" alt=\"\"></figure><p>开源的鸿蒙项目名为 OpenHarmony。OpenHarmony 定位是一款面向全场景的开源分布式操作系统。</p><p>根据介绍，OpenHarmony 在传统单设备系统能力的基础上，创造性地提出了基于同一套系统能力适配多种终端形态的理念，支持多种终端设备上运行，第一个版本支持 128K-128M 设备上运行。</p><p>开发者将获得模拟器、SDK 包以及 IDE 工具，2020 年底首先对国内开发者发布针对智能手机的 HarmonyOS beta 版本。</p><p>会上同时宣布，OpenHarmony 捐献给<a href=\"https://www.oschina.net/news/118490/openatom-foundation-appeared\">开放原子开源基金会</a>（OpenAtom Foundation）。开放原子开源基金会是中国首个，也是目前唯一一个以开源为主题的基金会，目前孵化项目包括百度超级链 XuperChain 与 OpenHarmony。</p><p>关于后续开源路径，华为表示：“从 9 月 10 日起，HarmonyOS 将面向大屏、手表、车机等 128KB-128MB 终端设备开源，2021 年 4 月将面向内存 128MB-4GB 终端设备开源，2021 年 10 月以后将面向 4GB 以上所有设备开源。”</p>', '/uploads/page/20200911/00078cdbf211dcc53388c4c013bfc7af.jpg', 1, '[11]', 18, '2020-09-21 13:05:28', 'now', 1, 46, 1, 0, NULL, NULL, 1, 1, '2020-09-11 18:12:37', '2020-09-21 16:54:49');
INSERT INTO `page` VALUES (19, 1, '开发一个渐进式Web应用程序（PWA）前都需要了解什么？', '自苹果推出了iPhone应用商店以来，App成为了我们生活中不可或缺的一部分，而对于实体业务也是如此，现在各行业都在推出自己的App，但有没有人想过这样一种场景，如果自己的潜在客户还没有安装你的App亦或是即便安装但因为客户的手机存储空间紧张而卸载掉了你的App？那有没有使App更轻量，更易安装的技术实现呢？答案是“有的”。', '<p>自苹果推出了iPhone应用商店以来，App成为了我们生活中不可或缺的一部分，而对于实体业务也是如此，现在各行业都在推出自己的App，但有没有人想过这样一种场景，如果自己的潜在客户还没有安装你的App亦或是即便安装但因为客户的手机存储空间紧张而卸载掉了你的App？那有没有使App更轻量，更易安装的技术实现呢？答案是“有的”。</p><p>渐进式Web应用程序就是为此而生的，它同时具备了Web应用功能和以前只有在原生应用才有的功能的特点，渐进式Web应用程序通过从主屏幕上的图标启动，也可以根据推送通知启动，加载时间几乎可以忽略不计，而且除了可以在线使用外，也可以打包成可离线使用。</p><p>最重要的是，渐进式Web应用程序在手机上创建方式也很简单，因为它们只是对你网站的增强，当有人在第一次访问你的网站时，PWA的功能在经过你授权后就会自动为你创建在手机上。</p><p>下面， 我们会一起来看看如何来创建一个属于自己的PWA应用。</p><h2><strong>要求</strong></h2><p>要开始学习本教程，您必须安装以下软件：</p><ul><li><strong>node</strong>&nbsp; 8.9 版本及以上 (<strong>https: // nodejs.org/en/download/</strong>).</li><li><strong>Yarn</strong>&nbsp;(<strong>https://yarnpkg.com</strong>)</li><li><strong>Git</strong>.</li></ul><p>作为本教程初始的工程，你可以clone以下Github库：</p><figure class=\"table\"><table><tbody><tr><td>1</td><td>git clone https: //github .com /petereijgermans11/progressive-web-app</td></tr></tbody></table></figure><p>然后，到以下目录中　　</p><figure class=\"table\"><table><tbody><tr><td>1</td><td>cd &nbsp; pwa-article / pwa-app-manifest-init</td></tr></tbody></table></figure><p>通过以下命令安装依赖并启动工程</p><figure class=\"table\"><table><tbody><tr><td>1</td><td>npm i &amp;&amp; npm start</td></tr></tbody></table></figure><p>通过以下地址打开应用：&nbsp;<strong>http:// localhost:8080</strong></p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911091659794-1973513684.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><h2><strong>应用的网址</strong></h2><p>有许多方法可以访问我的本地主机：为了从远程访问发布在你机器上的8080端口的地址。为此，您可以使用ngrok。请参阅：https://ngrok.com/</p><p>使用以下命令安装ngrok：&nbsp;</p><figure class=\"table\"><table><tbody><tr><td>1</td><td>npm &nbsp;install &nbsp; -g ngrok</td></tr></tbody></table></figure><p>在终端中运行以下命令。该命令为您生成一个<i>可供外部访问的URL</i>。</p><figure class=\"table\"><table><tbody><tr><td>1</td><td>ngrok http 8080</td></tr></tbody></table></figure><p>然后在Chrome中的<i>移动设备</i>上浏览至生成的网址。</p><h2><strong>PWA需要的技术组件是什么？</strong></h2><p>PWA有三个重要的技术组件协调工作，包括：</p><p>Manifest清单文件，Service Worker和在https下运行。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911091735435-1526854440.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><h3><strong>Manifest清单文件</strong></h3><p>清单文件是一个JSON配置文件，其中包含了PWA的基础信息，例如应用的icon，Web应用程序名称及背景颜色。如果浏览器检测到网站存在PWA清单文件，Chrome会自动出现“添加到主屏幕”按钮。如果用户点击同意，该图标将被添加到主屏幕，并且将安装PWA。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911091748126-968334782.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><h4><strong>创建一个Manifest.json</strong></h4><p>PWA的Manifest.json文件如下所示：</p><p>JSON格式</p><figure class=\"table\"><table><tbody><tr><td><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p><p>10</p><p>11</p><p>12</p><p>13</p><p>14</p><p>15</p><p>16</p><p>17</p><p>18</p><p>19</p><p>20</p><p>21</p></td><td><p>{</p><p>&nbsp; &nbsp;\"name\" : &nbsp;\"Progressive Selfies\" ,</p><p>&nbsp; &nbsp;\"short_name\" : &nbsp;\"PWA Selfies\" ,</p><p>&nbsp; &nbsp;\"icons\" : [</p><p>&nbsp;&nbsp;&nbsp; &nbsp;{</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;\"src\" : &nbsp;\"/src/images/icons/app-icon-192x192.png\" ,</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;\"type\" : &nbsp;\"image/png\" ,</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;\"sizes\" : &nbsp;\"192x192\"</p><p>&nbsp;&nbsp;&nbsp; &nbsp;},</p><p>&nbsp;&nbsp;&nbsp; &nbsp;{</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;\"src\" : &nbsp;\"/src/images/icons/app-icon-512x512.png\" ,</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;\"type\" : &nbsp;\"image/png\" ,</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;\"sizes\" : &nbsp;\"512x512\"</p><p>&nbsp;&nbsp;&nbsp; &nbsp;}</p><p>&nbsp; &nbsp;],</p><p>&nbsp; &nbsp;\"start_url\" : &nbsp;\"/index.html\" ,</p><p>&nbsp; &nbsp;\"scope\" : &nbsp;\".\" ,</p><p>&nbsp; &nbsp;\"display\" : &nbsp;\"standalone\" ,</p><p>&nbsp; &nbsp;\"background_color\" : &nbsp;\"#fff\" ,</p><p>&nbsp; &nbsp;\"theme_color\" : &nbsp;\"#3f51b5\"</p><p>}</p></td></tr></tbody></table></figure><h4><strong>告诉浏览器你应用的清单</strong></h4><p>在与<strong>index.html&nbsp;</strong>文件相同的级别的目录中创建<strong>Manifest.json</strong>文件。清单文件创建后，将清单文件引用链接添加到index.html中。</p><figure class=\"table\"><table><tbody><tr><td>1</td><td>&lt; link &nbsp; rel=”manifest” href=”/manifest.json”&gt;</td></tr></tbody></table></figure><h4><strong>Manifest&nbsp;属性介绍</strong></h4><p>Manifest有很多配置属性，接下来我们会对其中的属性做一个简单的介绍</p><ul><li><strong>name、short_name</strong><i>：指定Web应用的名称，short_name是该应用的简称，当没有足够空间展示应用的name属性时，系统就会使用short_name 。</i></li><li>l&nbsp; <strong>display</strong>：display属性指定Web应用的显示模式，它有四个值可供配置：fullscreen、standalone、minimal-ui和browser，但一般常用的属性就是fullscreen和standalone。<ul><li><strong>fullscreen</strong>：全屏显示</li><li><strong>standalone</strong>：这种模式下打开的应用不会出现浏览器的地址栏，所以因此看起来更像是一个原生应用</li><li><strong>minimal-ui、browser</strong>：和使用浏览器访问区别不大。</li></ul></li><li>l&nbsp; <strong>orientation</strong>：控制Web应用的显示的方向及禁止手机转屏。</li><li>l&nbsp; <strong>icons、background_color</strong>：icon用于指定应用图标，background_color是应用加载完成前的背景色，通过设置这两个属性，可组合成应用的Splash Screen。</li><li>l&nbsp; <strong>theme_color</strong>：定义应用程序的默认主题颜色。</li><li>l&nbsp; <strong>description</strong>：设置应用的一段描述内容。</li><li>&nbsp;</li></ul><p>以上是pwa 清单文件属性的一些说明，我们通过将设置完成的清单文件并将其放置在与<strong>index.html&nbsp;</strong>文件同级的目录中即可完成清单文件的添加。</p><p>打开Chrome开发者工具 – Application - Manifest，查看添加的清单文件是否加载完成，如果没有下图的信息，我们可以通过重新启动服务器&nbsp; npm start来重新加载。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911092202601-445887303.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><h3><strong>什么是Service Worker？</strong></h3><p>Service Worker(SW) 是一段JavaScript，它作为浏览器和网络服务器间的代理。Service Worker可以在基于浏览器的 web 应用中实现如离线缓存、消息推送、静默更新等 native 应用常见的功能，以给 web 应用提供更好更丰富的使用体验。</p><p>另外，这个API还允许利用缓存来支持离线体验，从而使开发人员可以完全控制用户的使用体验　　</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911092220832-2084132304.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><h4><strong>Service Worker生命周期</strong></h4><p>对于Service Worker，基本设置的步骤如下：</p><ul><li>首先应注册SW，如果SW已注册，浏览器会根据于安装事件自动开始安装。</li><li>安装SW后，它将收到激活事件。此激活事件可用于清理SW早期版本的中使用的资源。</li></ul><p>　</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911092235749-1220493999.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>实际操作应该首先创建一个和index.html同级，名为sw.js的空文件。然后再index.html文件中，添加一个base标签，如下：</p><figure class=\"table\"><table><tbody><tr><td>1</td><td>&lt; base &nbsp; href=”/”&gt;</td></tr></tbody></table></figure><p>最后，在src/js/app.js中添加以下代码注册SW。此代码将在页面 “&nbsp;加载&nbsp;”&nbsp;过程中被激活。</p><p>你可以打开Chrome DevTools – Application - Service Worker 中检查SW是否已经启用。</p><figure class=\"table\"><table><tbody><tr><td><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p><p>10</p><p>11</p><p>12</p><p>13</p><p>14</p><p>15</p><p>16</p><p>17</p><p>18</p><p>19</p></td><td><p>window.addEventListener( \'load\' , () =&gt; {</p><p>&nbsp;&nbsp;&nbsp; &nbsp;const base = document.querySelector( \'base\' );</p><p>&nbsp;&nbsp;&nbsp; &nbsp;let &nbsp; baseUrl = base &amp;&amp; base.href || &nbsp;\'\' ;</p><p>&nbsp;&nbsp;&nbsp; &nbsp;if &nbsp; (!baseUrl.endsWith( \'/\' )) {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;baseUrl = `${baseUrl}/`;</p><p>&nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;</p><p>&nbsp; &nbsp;</p><p>&nbsp;&nbsp;&nbsp; &nbsp;if &nbsp; ( \'serviceWorker\' &nbsp; in &nbsp; navigator) {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;navigator.serviceWorker.register(`${baseUrl}sw.js`)</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;.then( registration =&gt; {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;// Registration was successful</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;console.log( \'ServiceWorker registration successful with scope: \' , registration.scope);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;})</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;. catch (err =&gt; {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;// registration failed :(</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;console.log( \'ServiceWorker registration failed: \' , err);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;});</p><p>&nbsp;&nbsp;&nbsp; &nbsp;}</p><p>});</p></td></tr></tbody></table></figure><p>以上这段代码主要的作用是检查SW的API&nbsp;在window对象的navigator&nbsp;属性中是否可用。window对象代表浏览器窗口。如果SW在navigator&nbsp;中可用，则在页面加载时立即注册SW。</p><p>虽然注册一个SW很简单，但在有些情况下我们依然会遇到无法注册Service Worker的问题，我们来简单看看无法注册SW的原因都有什么并如何解决：</p><ul><li>您的应用程序无法在HTTPS下运行。在开发过程中，你可以通过<i>localhost</i>使用SW&nbsp;。但如果将其部署在网站上时，则需要启用HTTPS。</li><li>SW的路径不正确。</li></ul><p>没有勾选Update on reload。　　</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911092329361-852278883.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><h4><strong>Service Worker&nbsp;事件</strong></h4><p>除了install和activate事件外，其他事件还有message、fetch、sync和push事件。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911092345574-1550875891.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><p>将以下代码添加到你的SW中以监听生命周期事件（安装和激活）：</p><p>&nbsp;</p><figure class=\"table\"><table><tbody><tr><td><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p></td><td><p>self.addEventListener( \'install\' , event =&gt; {</p><p>&nbsp;&nbsp;&nbsp; &nbsp;console.log( \'[Service Worker] Installing Service Worker ...\' , event);</p><p>&nbsp;&nbsp;&nbsp; &nbsp;event.waitUntil(self.skipWaiting());</p><p>});</p><p>self.addEventListener( \'activate\' , event =&gt; {</p><p>&nbsp;&nbsp;&nbsp; &nbsp;console.log( \'[Service Worker] Activating Service Worker ...\' , event);</p><p>&nbsp;&nbsp;&nbsp; &nbsp;return &nbsp; self.clients.claim();</p><p>});</p></td></tr></tbody></table></figure><p>install回调调用skipWaiting()函数来触发activate事件，并告诉Service Worker立即开始工作，而无需等待用户浏览或重新加载页面。</p><p>skipWaiting()函数强制等待中的Service Worker成为活动的Service Worker。self.skipWaiting()函数也可以和self.clients.claim()函数一起使用，以确保对底层Service Worker的更新立即生效。</p><p>在这种情况下，self-property 代表窗口对象（即你的浏览器窗口）。</p><h3><strong>添加到主屏幕按钮</strong></h3><p>\"添加到主屏幕按钮\" 允许用户在其设备上安装PWA。为了真正用这个按钮安装PWA，你必须在SW中定义一个fetch事件处理程序。让我们在sw.js中解决这个问题。</p><figure class=\"table\"><table><tbody><tr><td><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p></td><td><p>self.addEventListener( \'fetch\' , event =&gt; {</p><p>&nbsp;&nbsp;&nbsp; &nbsp;console.log( \'[Service Worker] Fetching something ....\' , event);</p><p>&nbsp;&nbsp;&nbsp; &nbsp;// This fixes a weird bug in Chrome when you open the Developer Tools</p><p>&nbsp;&nbsp;&nbsp; &nbsp;if &nbsp; (event.request.cache === &nbsp;\'only-if-cached\' &nbsp; &amp;&amp; event.request.mode !== &nbsp;\'same-origin\' ) {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;return ;</p><p>&nbsp;&nbsp;&nbsp; &nbsp;}</p><p>&nbsp;&nbsp;&nbsp; &nbsp;event.respondWith(fetch(event.request));</p><p>});</p></td></tr></tbody></table></figure><h3><strong>Service Worker缓存</strong></h3><p>Service Worker的强大之处在于其拦截HTTP请求的能力。在这一步中，我们使用这个选项来拦截HTTP请求和响应，直接从缓存为用户提供闪电般快速的响应。</p><h4><strong>在Service Worker安装期间进行预缓存&nbsp;</strong></h4><p>当用户第一次访问你的网站时，SW会开始自行安装。在这个安装阶段，你可以将PWA使用的所有页面、脚本和样式文件下载并缓存起来，以下是完成这项工作的sw.js文件代码：　　</p><figure class=\"table\"><table><tbody><tr><td><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p><p>10</p><p>11</p><p>12</p><p>13</p><p>14</p><p>15</p><p>16</p><p>17</p><p>18</p><p>19</p><p>20</p><p>21</p><p>22</p><p>23</p><p>24</p><p>25</p><p>26</p><p>27</p></td><td><p>const CACHE_STATIC_NAME = &nbsp;\'static\' ;</p><p>const URLS_TO_PRECACHE = [</p><p>&nbsp;&nbsp;&nbsp; &nbsp;\'/\' ,</p><p>&nbsp;&nbsp;&nbsp; &nbsp;\'index.html\' ,</p><p>&nbsp;&nbsp;&nbsp; &nbsp;\'src/js/app.js\' ,</p><p>&nbsp;&nbsp;&nbsp; &nbsp;\'src/js/feed.js\' ,</p><p>&nbsp;&nbsp;&nbsp; &nbsp;\'src/lib/material.min.js\' ,</p><p>&nbsp;&nbsp;&nbsp; &nbsp;\'src/css/app.css\' ,</p><p>&nbsp;&nbsp;&nbsp; &nbsp;\'src/css/feed.css\' ,</p><p>&nbsp;&nbsp;&nbsp; &nbsp;\'src/images/main-image.jpg\' ,</p><p>&nbsp;&nbsp;&nbsp; &nbsp;\'https://fonts.googleapis.com/css?family=Roboto:400,700\' ,</p><p>&nbsp;&nbsp;&nbsp; &nbsp;\'https://fonts.googleapis.com/icon?family=Material+Icons\' ,</p><p>];</p><p>self.addEventListener( \'install\' , event =&gt; {</p><p>&nbsp;&nbsp;&nbsp; &nbsp;console.log( \'[Service Worker] Installing Service Worker ...\' , event);</p><p>&nbsp;&nbsp;&nbsp; &nbsp;event.waitUntil(</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;caches.open(CACHE_STATIC_NAME)</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;.then(cache =&gt; {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;console.log( \'[Service Worker] Precaching App Shell\' );</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;cache.addAll(URLS_TO_PRECACHE);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;})</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;.then(() =&gt; {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;console.log( \'[ServiceWorker] Skip waiting on install\' );</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;return &nbsp; self.skipWaiting();</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;})</p><p>&nbsp;&nbsp;&nbsp; &nbsp;);</p><p>});</p></td></tr></tbody></table></figure><p>这段代码使用安装事件，并在安装阶段添加了一个URLS_TO_PRECACHE数组。一旦调用开启缓存函数（caches.open），你就可以使用cache.addAll()函数来缓存数组中的文件。通过event.waitUntil()方法使用JavaScript promise来知道安装需要多长时间以及是否成功。</p><p>安装事件会调用self.skipWaiting()直接激活SW。如果所有文件都已被成功缓存，SW就会被安装。但如果其中一个文件无法下载，则安装步骤将会失败。在Chrome开发者工具中，你可以检查缓存（在Cache Storage中）是否被URLS_TO_PRECACHE数组中的静态文件填充。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911092452670-565678013.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><p>但是，如果你查看Network选项卡，文件仍然是通过网络获取的。原因是虽然缓存已经准备就绪了，但我们并没有从缓存中读取引用资源。所以为了完成这部分工作，我们首先要监听应用的fetch事件，然后拦截并从缓存中获取资源，让我们看看下面的代码吧：<strong>&nbsp;</strong></p><p>&nbsp;</p><figure class=\"table\"><table><tbody><tr><td><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p><p>10</p><p>11</p><p>12</p><p>13</p></td><td><p>self.addEventListener( \'fetch\' , event =&gt; {</p><p>&nbsp;&nbsp;&nbsp; &nbsp;console.log( \'[Service Worker] Fetching something ....\' , event);</p><p>&nbsp;&nbsp;&nbsp; &nbsp;event.respondWith(</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;caches.match(event.request)</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;.then(response =&gt; {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;if &nbsp; (response) {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;console.log(response);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;return &nbsp; response;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;}</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;return &nbsp; fetch(event.request);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;})</p><p>&nbsp;&nbsp;&nbsp; &nbsp;);</p><p>});</p></td></tr></tbody></table></figure><p>我们使用caches.match()函数检查传入的URL是否与当前缓存中可能存在的资源匹配。如果匹配，我们就返回该缓存资源，但如果该资源不存在于缓存中，我们就像正常情况下一样继续获取请求的资源。</p><p>在Service Worker安装并激活后，刷新页面并再次检查网络选项卡。现在，Service Worker将拦截HTTP请求，并从缓存中即时加载相应的资源，而不是向服务器发出网络请求。</p><p>现在，如果我们在网络选项卡中设置离线模式，我们的应用也依然能正常访问。</p><h3><strong>后台传输</strong></h3><p>Background Fetch API是SW的后台功能，它允许用户在后台下载大文件、视频和音乐等资源。在获取/传输过程中，你的用户即便关闭标签，乃至关闭整个浏览器，也不会清除传输任务。当用户再次打开浏览器后，传输过程将恢复。这个API也可以将传输的进度可以显示给用户，用户可以取消或暂停这个过程。</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911092515696-1508254378.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>默认情况下，后台传输功能是不可用的，你必须通过url(chrome://flags/#enable-experimental-web-platform-features)允许chrome的“Experimental Web Platform features”选项</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911092525677-798480100.png\" alt=\"\"></figure><p>&nbsp;</p><p>&nbsp;</p><p>以下是如何实现此类后台传输的示例。</p><p>在你的index.html文件中添加ID为“ bgFetchButton”&nbsp;的按钮</p><figure class=\"table\"><table><tbody><tr><td>1</td><td>&lt; button &nbsp; id=”bgFetchButton”&gt;Store assets locally&lt;/ button &gt;</td></tr></tbody></table></figure><p>然后，在加载事件处理程序中的app.js中添加用于执行后台传输的代码</p><figure class=\"table\"><table><tbody><tr><td><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p><p>10</p><p>11</p><p>12</p><p>13</p></td><td><p>window.addEventListener(‘load’, () =&gt; {</p><p>...</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;bgFetchButton = document.querySelector(‘ #bgFetchButton’);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;bgFetchButton.addEventListener(‘click’, async event =&gt; {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;try &nbsp; {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;const registration = await navigator.serviceWorker.ready;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;registration.backgroundFetch.fetch(‘my-fetch’, [ new&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; Request(`${baseUrl}src/images/main-image-lg.jpg`)]);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;} &nbsp;catch &nbsp; (err) {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;console.error(err);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;}</p><p>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;});</p><p>...</p><p>});</p></td></tr></tbody></table></figure><p>上面的代码在以下条件下开始执行后台传输：</p><ul><li>用户点击ID为bgFetchButton的按钮</li><li>SW已注册</li></ul><p>后台传输必须在异步函数中执行，因为传输过程不能阻塞用户界面。</p><p>传输完成后放入缓存</p><figure class=\"table\"><table><tbody><tr><td><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p><p>10</p><p>11</p><p>12</p><p>13</p><p>14</p><p>15</p><p>16</p></td><td><p>self.addEventListener(‘backgroundfetchsuccess’, event =&gt; {</p><p>&nbsp; &nbsp;console.log(‘[Service Worker]: Background Fetch Success’, event.registration);&nbsp;&nbsp; event.waitUntil(</p><p>&nbsp;&nbsp; &nbsp;(async &nbsp;function () {</p><p>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;try &nbsp; {</p><p>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;// Iterating the records to populate the cache</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;const cache = await caches.open(event.registration.id); const records =&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; await event.registration.matchAll(); const promises = records.map(async&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; record =&gt; {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;const response = await record.responseReady;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;await cache.put(record.request, response);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;});</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;await Promise.all(promises);</p><p>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;} &nbsp;catch &nbsp; (err) {</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;console.log(‘[Service Worker]: Caching error’);</p><p>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;}</p><p>&nbsp;&nbsp; &nbsp;})()</p><p>&nbsp; &nbsp;);</p><p>});</p></td></tr></tbody></table></figure><p>这段代码由以下步骤组成：</p><ul><li>l&nbsp; 当Background Fetch传输完成，你的SW将收到Background Fetch成功事件。</li><li>l&nbsp; 创建并打开一个与registration.id同名的新缓存。</li><li>l&nbsp; 通过registration.matchAll()获取所有记录并遍历。</li></ul><p>最后，通过Promise.all()，执行所有的承诺。　　</p><figure class=\"image\"><img src=\"https://oscimg.oschina.net/oscnet/139239-20200911092649673-787391618.png\" alt=\"\"></figure><p>&nbsp;</p><h2><strong>总结&nbsp;</strong></h2><p>在本文中我们讨论了PWA的基础组成部分的其中两部分：Manifest、Service Worker的基础功能介绍，因为HTTPS之前我们已经有过一些讨论了<a href=\"https://www.cnblogs.com/powertoolsteam/p/http2https.html\">https://www.cnblogs.com/powertoolsteam/p/http2https.html</a>，</p><p>后面如果大家感兴趣，我们可用一起讨论一些PWA的高级功能，这些功能可以为你的应用提供调用硬件的能力。如果有任何问题，欢迎通过评论区留言告诉我。&nbsp;</p>', '/uploads/page/20200911/1435de09be29041431d5791fe9784fc8.jpg', 1, '[1, 2, 10]', 58, '2020-09-21 17:19:51', 'timing', 1, 19, 0, 0, NULL, NULL, 1, 1, '2020-09-11 18:15:31', '2020-09-23 09:53:23');
INSERT INTO `page` VALUES (20, 1, '谷歌推出 Go 版 Android 11，适用于入门级设备', 'Go 版 Android 11 最大的亮点是可以在 2GB 或更少的 RAM 的设备上运行，而去年发布的 Android 10（Go 版）仅能用于 RAM 小于 1.5GB 的设备。今年七月，曾有泄露的谷歌文档显示“谷歌提高 Android RAM 要求，低于 2GB 将强制使用 Android Go”。从这个方面来讲，这也是 Go 版 Android 11 此次在运行内存上有所提升的一大原因。', '<p><a href=\"https://www.oschina.net/news/118473/android-11-released\">Android 11</a> 刚刚发布，谷歌的 <a href=\"https://blog.google/products/android/android-11-go-edition-new-features-coming-more-devices/\">Go 版本 Android 11</a> 也紧随其后。Android Go 版本最初于 2018 年推出，旨在为入门级设备提供智能手机体验。</p><figure class=\"image\"><img src=\"https://static.oschina.net/uploads/space/2020/0911/084834_vNDN_4105562.png\" alt=\"\"></figure><p>Go 版 Android 11 最大的亮点是可以在 2GB 或更少的 RAM 的设备上运行，而去年发布的 Android 10（Go 版）仅能用于 RAM 小于 1.5GB 的设备。</p><p>今年七月，曾有泄露的谷歌文档显示“<a href=\"https://www.oschina.net/news/117441/google-android-ram-requirements-android-go\">谷歌提高 Android RAM 要求，低于 2GB 将强制使用 Android Go</a>”。从这个方面来讲，这也是 Go 版 Android 11 此次在运行内存上有所提升的一大原因。</p><p>此外，它还提供了额外的 270MB RAM，这意味着用户现在能够在后台同时运行四个应用程序。以及 900MB 的额外空间，用来存储更多应用程序和媒体文件。谷歌表示，新的 Android（Go 版）比上一个版本提高了 20％ 的应用启动速度。</p><figure class=\"image\"><img src=\"https://static.oschina.net/uploads/space/2020/0911/084922_RYWc_4105562.gif\" alt=\"\"></figure><p>与 Android 11 一样，Go 版本同样带来了一站式消息栏和隐私方面的诸多新特性，包括一次性访问权限、长期不使用的程序权限重置等。这个版本还为入门级设备添加了手势导航操作，用户可以更自如地在应用之间切换。</p><p>新的安全文件夹功能算是一个小亮点。用户可将个人文件存储在 4 位 PIN 加密的文件夹中，以防止他人打开或访问个人文件。但仅在谷歌文档中可用。</p><p>下个月开始，Go 版 Android 11 将在所有具有 2GB 内存的设备上陆续提供。</p>', '/uploads/page/20200911/205fc67d0be5fa4563291818bccb5000.jpg', 1, '[25]', 6, '2020-09-11 18:17:58', 'now', 1, 673, 0, 0, NULL, NULL, 1, 1, '2020-09-11 18:17:58', '2020-09-21 16:54:47');
INSERT INTO `page` VALUES (21, 3, '鸿蒙内核标准库与 Linux 标准库的差异', '本文描述了 OpenHarmony 内核承载的标准库与 Linux 标准库之间存在的关键差异。', '<p>本文描述了 OpenHarmony 内核承载的标准库与 Linux 标准库之间存在的关键差异。</p><h2><strong>进程</strong></h2><ol><li>OpenHarmony 用户态进程优先级只支持静态优先级且用户态可配置的优先级范围为10(最高优先级)-31(最低优先级）。</li><li>OpenHarmony 用户态线程优先级只支持静态优先级且用户态可配置的优先级范围为0(最高优先级)-31(最低优先级）。</li><li>OpenHarmony 调度策略支持 SCHED_RR 和 SCHED_FIFO。</li><li>sched_yield() 为进程主动放弃 CPU；thrd_yield() 为线程主动放弃 CPU。</li></ol><h2><strong>内存</strong></h2><h2><strong>与 Linux mmap 的差异</strong></h2><p>mmap接口原型为：void *mmap (void *addr, size_t length, int prot, int flags, int fd, off_t offset)。</p><p>其中，参数fd的生命周期实现与Linux glibc存在差异。具体体现在，glibc在成功调用mmap进行映射后，可以立即释放fd句柄。在OpenHarmony内核中，不允许用户在映射成功后立即关闭相关fd，只允许在取消映射munmap后再进行fd的close操作。如果用户不进行fd的close操作，操作系统将在进程退出时对该fd进行回收。</p><h2><strong>代码举例</strong></h2><p>Linux目前支持的情况如下：</p><p>int main(int argc, char *argv[])\r\n{\r\n &nbsp; &nbsp;int fd;\r\n &nbsp; &nbsp;void *addr = NULL;\r\n &nbsp; &nbsp;...\r\n &nbsp; &nbsp;fd = open(argv[1], O_RDONLY);\r\n &nbsp; &nbsp;if (fd == -1){\r\n &nbsp; &nbsp; &nbsp; &nbsp;perror(\"open\");\r\n &nbsp; &nbsp; &nbsp; &nbsp;exit(EXIT_FAILURE);\r\n &nbsp; &nbsp;}\r\n &nbsp; &nbsp;addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);\r\n &nbsp; &nbsp;if (addr == MAP_FAILED) {\r\n &nbsp; &nbsp; &nbsp; &nbsp;perror(\"mmap\");\r\n &nbsp; &nbsp; &nbsp; &nbsp;exit(EXIT_FAILURE);\r\n &nbsp; &nbsp;}\r\n &nbsp; &nbsp;close(fd); /* close immediately, OpenHarmony do not support this way */ \r\n &nbsp; &nbsp;...\r\n &nbsp; &nbsp;exit(EXIT_SUCCESS);\r\n}</p><p>OpenHarmony支持的情况如下：</p><p>int main(int argc, char *argv[])\r\n{\r\n &nbsp; &nbsp;int fd;\r\n &nbsp; &nbsp;void *addr = NULL;\r\n &nbsp; &nbsp;...\r\n &nbsp; &nbsp;fd = open(argv[1], O_RDONLY);\r\n &nbsp; &nbsp;if (fd == -1){\r\n &nbsp; &nbsp; &nbsp; &nbsp;perror(\"open\");\r\n &nbsp; &nbsp; &nbsp; &nbsp;exit(EXIT_FAILURE);\r\n &nbsp; &nbsp;}\r\n &nbsp; &nbsp;addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, offset);\r\n &nbsp; &nbsp;if (addr == MAP_FAILED) {\r\n &nbsp; &nbsp; &nbsp; &nbsp;perror(\"mmap\");\r\n &nbsp; &nbsp; &nbsp; &nbsp;exit(EXIT_FAILURE);\r\n &nbsp; &nbsp;}\r\n &nbsp; &nbsp;...\r\n &nbsp; &nbsp;munmap(addr, length);\r\n &nbsp; &nbsp;close(fd); /* close after munmap */\r\n &nbsp; &nbsp;exit(EXIT_SUCCESS);\r\n}</p><h2><strong>文件系统</strong></h2><p>**系统目录：**用户无法对其进行修改，或是设备挂载。包含/dev，/proc，/app，/bin，/data，/etc，/lib，/system，/usr目录。</p><p><strong>用户目录：用户可以在该目录下进行文件创建、读写，但不能进行设备挂载</strong>。用户目录指/storage目录。</p><p>除<strong>系统目录</strong>与<strong>用户目录</strong>之外，用户可以自行创建文件夹进行设备的挂载。但是要注意，已挂载的文件夹及其子文件夹不允许重复或者嵌套挂载，非空文件夹不允许挂载。</p><h2><strong>信号</strong></h2><ul><li>信号默认行为不支持STOP、CONTINUE、COREDUMP功能。</li><li>无法通过信号唤醒正在睡眠状态（举例：进程调用sleep函数进入睡眠）的进程。原因：信号机制无唤醒功能，当且仅当进程被CPU调度运行时才能处理信号内容。</li><li>进程退出后会发送SIGCHLD给父进程，发送动作无法取消。</li><li>信号仅支持1-30号信号，接收方收到多次同一信号，仅执行一次回调函数。</li></ul><h2><strong>Time</strong></h2><p>OpenHarmony当前时间精度以tick计算，系统默认10ms/tick。sleep、timeout系列函数时间误差&lt;=20ms。</p>', '/uploads/page/20200911/33b1c80fc3743f5d0aeba96a0be50d0c.jpg', 1, '[11]', 3, '2020-09-11 18:19:59', 'now', 1, 35, 0, 0, NULL, NULL, 1, 1, '2020-09-11 18:19:59', '2020-09-21 16:54:21');
INSERT INTO `page` VALUES (22, 3, '鸿蒙开发快速入门之：Hi3861 开发板（2）环境搭建', '这是 Hi3861 开发板进行 OpenHarmony 开发快速入门的第二篇，主要学习如何搭建环境。', '<p>这是&nbsp;Hi3861 开发板进行&nbsp;OpenHarmony 开发快速入门的第二篇，主要学习如何搭建环境。</p>\r\n<h2><strong>硬件要求</strong></h2>\r\n<ul>\r\n<li>Linux服务器</li>\r\n<li>Windows工作台（主机电脑）</li>\r\n<li>Hi3861 WLAN模组</li>\r\n<li>USB Type-C线（Windows工作台通过USB与Hi3861 WLAN模组连接）</li>\r\n</ul>\r\n<p>各硬件连接关系如下图所示。</p>\r\n<p><strong>图 1</strong>&nbsp;硬件连线图<br />&nbsp;</p>\r\n<figure class=\"image\"><img src=\"https://openharmony.gitee.com/openharmony/docs/raw/master/quick-start/figures/%E7%A1%AC%E4%BB%B6%E8%BF%9E%E7%BA%BF%E5%9B%BE.png\" alt=\"\" /></figure>\r\n<h2><strong>软件系统要求</strong></h2>\r\n<p><strong>表 1</strong>&nbsp;Hi3861 WLAN模組开发平台要求</p>\r\n<figure class=\"table\">\r\n<table>\r\n<tbody>\r\n<tr>\r\n<th>硬件</th>\r\n<th>软件</th>\r\n<th>描述</th>\r\n<th>备注</th>\r\n</tr>\r\n<tr>\r\n<th>Linux编译服务器</th>\r\n<th>操作系统</th>\r\n<th>Ubuntu16.04及以上64位系统版本，Shell使用bash</th>\r\n<th>开发人员可以在Windows工作台中进行程序开发，或者远程登录到Linux服务器进行程序开发。</th>\r\n</tr>\r\n<tr>\r\n<th>Windows工作台</th>\r\n<th>操作系统</th>\r\n<th>Windows XP/Windows7/Windows10</th>\r\n<th>&nbsp;</th>\r\n</tr>\r\n</tbody>\r\n</table>\r\n</figure>\r\n<h2><strong>Linux构建工具要求</strong></h2>\r\n<p>Linux服务器通用环境配置需要的工具及其获取途径如下表所示。</p>\r\n<p><strong>表 2</strong>&nbsp;Linux服务器开发工具及获取途径</p>\r\n<figure class=\"table\">\r\n<table>\r\n<tbody>\r\n<tr>\r\n<th>开发工具</th>\r\n<th>用途</th>\r\n<th>获取途径</th>\r\n</tr>\r\n<tr>\r\n<th>交叉编译器gcc_riscv32</th>\r\n<th>交叉编译工具</th>\r\n<th><a href=\"http://tools.harmonyos.com/mirrors/gcc_riscv32/7.3.0/linux/gcc_riscv32-linux-7.3.0.tar.gz\">http://tools.harmonyos.com/mirrors/gcc_riscv32/7.3.0/linux/gcc_riscv32-linux-7.3.0.tar.gz</a></th>\r\n</tr>\r\n<tr>\r\n<th>Python3.7+</th>\r\n<th>编译构建工具</th>\r\n<th><a href=\"https://www.python.org/ftp/python/3.8.5/Python-3.8.5.tgz\">https://www.python.org/ftp/python/3.8.5/Python-3.8.5.tgz</a></th>\r\n</tr>\r\n<tr>\r\n<th>SCons3.0.4+</th>\r\n<th>编译构建工具</th>\r\n<th>通过互联网获取</th>\r\n</tr>\r\n<tr>\r\n<th>bash</th>\r\n<th>命令处理器</th>\r\n<th>通过互联网获取</th>\r\n</tr>\r\n<tr>\r\n<th>build-essential</th>\r\n<th>编译依赖的基础软件包</th>\r\n<th>通过互联网获取</th>\r\n</tr>\r\n<tr>\r\n<th>gn</th>\r\n<th>产生ninja编译脚本</th>\r\n<th><a href=\"http://tools.harmonyos.com/mirrors/gn/1523/linux/gn.1523.tar\">http://tools.harmonyos.com/mirrors/gn/1523/linux/gn.1523.tar</a></th>\r\n</tr>\r\n<tr>\r\n<th>ninja</th>\r\n<th>执行ninja编译脚本</th>\r\n<th><a href=\"http://tools.harmonyos.com/mirrors/ninja/1.9.0/linux/ninja.1.9.0.tar\">http://tools.harmonyos.com/mirrors/ninja/1.9.0/linux/ninja.1.9.0.tar</a></th>\r\n</tr>\r\n</tbody>\r\n</table>\r\n</figure>\r\n<h2><strong>Windows开发工具要求</strong></h2>\r\n<p><strong>表 3</strong>&nbsp;Windows工作台开发工具及获取途径</p>\r\n<figure class=\"table\">\r\n<table>\r\n<tbody>\r\n<tr>\r\n<th>开发工具</th>\r\n<th>用途</th>\r\n<th>获取途径</th>\r\n</tr>\r\n<tr>\r\n<th>Visual Studio Code</th>\r\n<th>代码编辑工具。</th>\r\n<th><a href=\"https://code.visualstudio.com/\">https://code.visualstudio.com/</a></th>\r\n</tr>\r\n<tr>\r\n<th>HUAWEI DevEco Device Tool</th>\r\n<th>\r\n<p>IDE开发工具，支持WLAN模组的代码编写、远程编译、版本烧录、串口调试等功能。</p>\r\n<p>说明：</p>\r\n<p>HUAWEI DevEco Device Tool是OpenHarmony面向智能设备开发者提供的一站式集成开发环境，支持OpenHarmony的组件按需定制，支持C/C++语言，以插件的形式部署在Visual Studio Code上。</p>\r\n</th>\r\n<th><a href=\"https://device.harmonyos.com/cn/ide\">https://device.harmonyos.com/cn/ide</a></th>\r\n</tr>\r\n<tr>\r\n<th>IPOP、PuTTY或其他超级终端（选其一）</th>\r\n<th>远程连接Linux编译服务器，连接模组串口工具。</th>\r\n<th>通过互联网获取（如：<a href=\"https://www.putty.org/\">https://www.putty.org/</a>）</th>\r\n</tr>\r\n<tr>\r\n<th>CH341SER.EXE</th>\r\n<th>USB转串口驱动。</th>\r\n<th><a href=\"http://www.wch.cn/search?q=ch340g&amp;t=downloads\">http://www.wch.cn/search?q=ch340g&amp;t=downloads</a></th>\r\n</tr>\r\n</tbody>\r\n</table>\r\n</figure>\r\n<h2><strong>安装编译基础环境</strong></h2>\r\n<h2><strong>连接Linux服务器</strong></h2>\r\n<p>使用Windows远程登录Linux，以PUTTY工具为例：</p>\r\n<p>打开<a href=\"https://www.putty.org/\">PuTTY工具</a>，输入Linux服务器IP地址，后点击&ldquo;open&rdquo;，打开连接。</p>\r\n<p><strong>图 2</strong>&nbsp;PuTTY界面示例图<br />&nbsp;</p>\r\n<figure class=\"image\"><img src=\"https://openharmony.gitee.com/openharmony/docs/raw/master/quick-start/figures/PuTTY%E7%95%8C%E9%9D%A2%E7%A4%BA%E4%BE%8B%E5%9B%BE.png\" alt=\"\" /></figure>\r\n<p>弹框告警选择&ldquo;是(Y)&rdquo;。</p>\r\n<p>弹出界面中输入账号并按回车键，继续输入密码并回车键。</p>\r\n<p><strong>图 3</strong>&nbsp;登录界面图<br />&nbsp;</p>\r\n<figure class=\"image\"><img src=\"https://openharmony.gitee.com/openharmony/docs/raw/master/quick-start/figures/%E7%99%BB%E5%BD%95%E7%95%8C%E9%9D%A2%E5%9B%BE.png\" alt=\"\" /></figure>\r\n<p>登录成功。</p>\r\n<p><strong>图 4</strong>&nbsp;登录成功界面<br />&nbsp;</p>\r\n<figure class=\"image\"><img src=\"https://openharmony.gitee.com/openharmony/docs/raw/master/quick-start/figures/%E7%99%BB%E5%BD%95%E6%88%90%E5%8A%9F%E7%95%8C%E9%9D%A2.png\" alt=\"\" /></figure>\r\n<h2><strong>将Linux shell改为bash</strong></h2>\r\n<p>查看shell是否为bash，在终端运行如下命令</p>\r\n<p>ls -l /bin/sh</p>\r\n<p>如果为显示为/bin/sh -&gt; bash则为正常，否则请按以下方式修改：</p>\r\n<p><strong>方法一</strong>：在终端运行如下命令，然后选择 no。</p>\r\n<p>sudo dpkg-reconfigure dash</p>\r\n<p><strong>方法二</strong>：先删除sh，再创建软链接。</p>\r\n<p>rm -rf /bin/sh sudo ln -s /bin/bash /bin/sh</p>\r\n<h2><strong>安装Python环境</strong></h2>\r\n<p>打开Linux编译服务器终端。</p>\r\n<p>输入命令&ldquo;python3 --version&rdquo;，查看Python版本号。需使用python3.7以上版本，否则请按以下步骤执行，以python3.8为例：</p>\r\n<p>如果Ubuntu 版本为18，运行\"sudo apt-get install python3.8\"</p>\r\n<p>如果Ubuntu 版本为16，请以下载包的方式安装python:</p>\r\n<ol>\r\n<li>python安装环境依赖(gcc, g++, make, zlib, libffi)请运行：</li>\r\n<li>获取<a href=\"https://www.python.org/ftp/python/3.8.5/Python-3.8.5.tgz\">python3.8.5安装包</a>，将其放至linux服务器中，运行 ：</li>\r\n<li>确定Python-3.8.5安装好后，运行\"which python3.8\"，将回显路径链接到\"/usr/bin/python\"，示例：</li>\r\n</ol>\r\n<p>安装Python包管理工具，运行&ldquo;sudo apt-get install python3-setuptools python3-pip -y&rdquo;命令。（需root/sudo权限安装），升级pip3运行\"sudo pip3 install --upgrade pip\"。</p>\r\n<p>或按官网方式安装Python包管理工具：下载\"curl&nbsp;<a href=\"https://bootstrap.pypa.io/get-pip.py\">https://bootstrap.pypa.io/get-pip.py</a>&nbsp;-o get-pip.py\"后，再执行\"python get-pip.py\"</p>\r\n<p>安装python模块setuptools，运行\"pip3 install setuptools\"</p>\r\n<p>运行&ldquo;sudo pip3 install kconfiglib&rdquo;命令，安装GUI menuconfig工具，建议安装Kconfiglib 13.2.0+版本。（需root/sudo权限安装）。</p>\r\n<p>或者按以下方法安装Kconfiglib 13.2.0+。</p>\r\n<p>下载.whl文件（例如：kconfiglib-13.2.0-py2.py3-none-any.whl）。</p>\r\n<p>下载路径：&ldquo;<a href=\"https://pypi.org/project/kconfiglib#files\">https://pypi.org/project/kconfiglib#files</a>&rdquo;</p>\r\n<p>运行&ldquo;sudo pip3 install kconfiglib-xxx.whl&rdquo;命令（例如：sudo pip3 install kconfiglib-13.2.0-py2.py3-none-any.whl），安装.whl文件（需root/sudo权限安装）。</p>\r\n<p>可能会遇到错误：\"subprocess.CalledProcessError: Command \'(\'lsb_release\', \'-a\')\' returned non-zero exit status 1.\"，解决方法：\"find / -name lsb_release\"，找到lsb_release位置并删除，如：\"rm -rf /usr/bin/lsb_release\"</p>\r\n<p>安装pycryptodome。运行&ldquo;sudo pip3 install pycryptodome&rdquo;命令，或者按照以下方式安装：</p>\r\n<blockquote>\r\n<figure class=\"image\"><img src=\"https://openharmony.gitee.com/openharmony/docs/raw/master/quick-start/public_sys-resources/icon-note.gif\" alt=\"\" /></figure>\r\n<p>&nbsp;<strong>说明：</strong></p>\r\n<ul>\r\n<li>安装升级文件签名依赖的Python组件包，包括：pycryptodome、six、ecdsa。</li>\r\n<li>安装ecdsa依赖six，请按文档要求，先安装six，再安装ecdsa。</li>\r\n</ul>\r\n</blockquote>\r\n<p>下载.whl文件（例如：pycryptodome-3.7.3-cp37-cp37m-manylinux1_x86_64.whl）。</p>\r\n<p>下载路径：&ldquo;<a href=\"https://pypi.org/project/pycryptodome/#files\">https://pypi.org/project/pycryptodome/#files</a>&rdquo;。</p>\r\n<p>运行&ldquo;sudo pip3 install pycryptodome-xxx.whl&rdquo;命令（例如：sudo pip3 install pycryptodome-3.7.3-cp37-cp37m-manylinux1_x86_64.whl），安装.whl文件（需root/sudo权限安装）。</p>\r\n<p>安装six。运行\"sudo pip3 install six --upgrade --ignore-installed six\"或者按照以下方式安装：</p>\r\n<p>下载.whl文件（例如：six-1.12.0-py2.py3-none-any.whl）。</p>\r\n<p>下载路径：&ldquo;<a href=\"https://pypi.org/project/six/#files\">https://pypi.org/project/six/#files</a>&rdquo;</p>\r\n<p>运行&ldquo;sudo pip3 install six-xxx.whl&rdquo;命令（例如：sudo pip3 install six-1.12.0-py2.py3-none-any.whl），安装.whl文件（需root/sudo权限安装）。</p>\r\n<p>安装ecdsa。运行\"sudo pip3 install ecdsa\"或者按照以下方式安装：</p>\r\n<p>下载.whl文件（例如：ecdsa-0.14.1-py2.py3-none-any.whl）。</p>\r\n<p>下载路径：&ldquo;<a href=\"https://pypi.org/project/ecdsa/#files\">https://pypi.org/project/ecdsa/#files</a>&rdquo;</p>\r\n<p>运行&ldquo;sudo pip3 install ecdsa-xxx.whl&rdquo;命令（例如：sudo pip3 install ecdsa-0.14.1-py2.py3-none-any.whl），安装.whl文件（需root/sudo权限安装）。</p>\r\n<h2><strong>安装Scons</strong></h2>\r\n<p>打开Linux编译服务器终端。</p>\r\n<p>安装SCons安装包（需root/sudo权限安装）。</p>\r\n<p>运行命令：&ldquo;sudo apt-get install scons -y&rdquo;。如果软件源中无法找到安装包，请按以下步骤处理：</p>\r\n<ol>\r\n<li>下载源码包（下载路径：&ldquo;&nbsp;<a href=\"https://scons.org/pages/download.html\">https://scons.org/pages/download.html</a>&nbsp;&rdquo;，推荐SCons版本是3.0.4+）。</li>\r\n<li>解压源码包到任意目录。</li>\r\n<li>安装源码包：进入解压目录，运行命令&ldquo;sudo python3 setup.py install&rdquo;（需root/sudo权限安装），等待安装完毕。</li>\r\n</ol>\r\n<p>输入命令&ldquo;scons -v&rdquo;，查看是否安装成功。如果安装成功，查询结果下图所示。</p>\r\n<p><strong>图 5</strong>&nbsp;SCons安装成功界面<br />&nbsp;</p>\r\n<figure class=\"image\"><img src=\"https://openharmony.gitee.com/openharmony/docs/raw/master/quick-start/figures/SCons%E5%AE%89%E8%A3%85%E6%88%90%E5%8A%9F%E7%95%8C%E9%9D%A2.png\" alt=\"\" /></figure>\r\n<h2><strong>安装编译工具环境</strong></h2>\r\n<blockquote>\r\n<figure class=\"image\"><img src=\"https://openharmony.gitee.com/openharmony/docs/raw/master/quick-start/public_sys-resources/icon-notice.gif\" alt=\"\" /></figure>\r\n<p>&nbsp;<strong>须知：</strong></p>\r\n<ul>\r\n<li>如果后续通过&ldquo;HPM组件方式&rdquo;或&ldquo;HPM包管理器命令行工具方式&rdquo;获取源码，不需要安装gn、ninja、gcc_riscv32编译工具。</li>\r\n<li>（推荐）如果后续通过&ldquo;镜像站点方式&rdquo;或&ldquo;代码仓库方式&rdquo;获取源码，需要安装gn、ninja、gcc_riscv32编译工具。 安装gn、ninja、gcc_riscv32编译工具时，请确保编译工具的环境变量路径唯一。</li>\r\n</ul>\r\n</blockquote>\r\n<h2><strong>安装gn</strong></h2>\r\n<ol>\r\n<li>打开Linux编译服务器终端。</li>\r\n<li><a href=\"http://tools.harmonyos.com/mirrors/gn/1523/linux/gn.1523.tar\">下载gn工具</a>。</li>\r\n<li>解压gn安装包至~/gn路径下：\"tar -xvf gn.1523.tar -C ~/\"。</li>\r\n<li>设置环境变量：\"vim ~/.bashrc\", 新增：\"export PATH=~/gn:$PATH\"。</li>\r\n<li>生效环境变量：\"source ~/.bashrc\"。</li>\r\n</ol>\r\n<h2><strong>安装ninja</strong></h2>\r\n<ol>\r\n<li>打开Linux编译服务器终端</li>\r\n<li><a href=\"http://tools.harmonyos.com/mirrors/ninja/1.9.0/linux/ninja.1.9.0.tar\">下载ninja工具</a>。</li>\r\n<li>解压ninja安装包至~/ninja路径下：\"tar -xvf ninja.1.9.0.tar -C ~/\"。</li>\r\n<li>设置环境变量：\"vim ~/.bashrc\", 新增：\"export PATH=~/ninja:$PATH\"。</li>\r\n<li>生效环境变量：\"source ~/.bashrc\"。</li>\r\n</ol>\r\n<h2><strong>安装gcc_riscv32（WLAN模组类编译工具链）</strong></h2>\r\n<blockquote>\r\n<figure class=\"image\"><img src=\"https://openharmony.gitee.com/openharmony/docs/raw/master/quick-start/public_sys-resources/icon-notice.gif\" alt=\"\" /></figure>\r\n<p>&nbsp;<strong>须知：</strong>&nbsp;Hi3861平台仅支持使用libgcc运行时库的静态链接，<strong>不建议开发者使用libgcc运行时库的动态链接，会导致商业分发时被GPL V3污染。</strong></p>\r\n</blockquote>\r\n<ol>\r\n<li>打开Linux编译服务器终端。</li>\r\n<li><a href=\"http://tools.harmonyos.com/mirrors/gcc_riscv32/7.3.0/linux/gcc_riscv32-linux-7.3.0.tar.gz\">下载gcc_riscv32工具</a>。</li>\r\n<li>解压gcc_riscv32安装包至/opt/gcc_riscv32路径下：\"tar -xvf gcc_riscv32-linux-7.3.0.tar.gz -C ~/\"。</li>\r\n<li>设置环境变量：\"vim ~/.bashrc\"，新增：\"export PATH=~/gcc_riscv32/bin:$PATH\"。</li>\r\n<li>生效环境变量：\"source ~/.bashrc\"。</li>\r\n<li>Shell命令行中输入&ldquo;riscv32-unknown-elf-gcc -v&rdquo;，如果能正确显示编译器版本号，表明编译器安装成功。</li>\r\n</ol>', '/uploads/page/20200921/4936ce93fdf80c871f5fb2852bd47eb8.jpg', 1, '[11]', 7, '2020-09-23 16:08:27', 'now', 1, 84, 0, 0, NULL, NULL, 1, 1, '2020-09-11 18:21:10', '2020-09-23 08:20:50');
INSERT INTO `page` VALUES (23, 3, '“心术不正”的人，身上有3个特征，趁早和他绝交！', '活到老学到老，在做人这个方面，永远有学不完的东西，人生就像是一本忏悔录，要不断的记录自己，纠正自己，最后成就自己，这虽然是一个很漫长的路程，却值得每一个人去践行。', '<p>“心术不正”的人，身上有这3个特征<br>&nbsp;</p><p>活到老学到老，在做人这个方面，永远有学不完的东西，人生就像是一本忏悔录，要不断的记录自己，纠正自己，最后成就自己，这虽然是一个很漫长的路程，却值得每一个人去践行。</p><p>在这个世界上，有很多形形色色的人，有真诚也有虚伪，有至死不渝也有忘恩负义，但是还好我们还有一颗良善的本心，人应该像一盏明灯，永远给别人指明道路，但是也别忘了，害人之心不可有，防人之心不可无。</p><p>“心术不正”的人，身上有3个特征，趁早和他绝交吧！</p><p>01.心机很深，投机取巧，常常想从别人身上获利</p><p>世界上有两种东西难以直视，一个是太阳，一个是人心。</p><p>人性是经不起考验的，所以才会在心里设起城府，人有心机本身不是一件坏事。</p><p>但是有些人总喜欢把心机用在不好的地方，投机取巧，挑拨离间，想用自己的小聪明从别人身上获利，这种损人利己的心机，恰恰是“心术不正”的表现。</p><p>02.招摇过市，喜欢揭人短处，张扬别人的丑事</p><p>人在社会上立足，凡事都要留有余地，不要把事情做绝，很多事情心里明白就好了，得饶人处且饶人，没有必要硬抓着别人的丑事不放，这对谁都没好处。</p><p>心术不正的人，永远是抬高自己，贬低别人，总是喜欢在公众场合张扬别人的丑事，恨不得全世界都知道自己比别人优秀。</p><p>殊不知三十年河东，三十年河西，那些被你嘲笑的人，总有一天会让你后悔都来不及，所以把快乐建立在别人痛苦之上的人，根本不配做朋友。</p><p>03.两面人，表面一套，背后做一套，虚情假意</p><p>有一种人，表面百般奉承，各种说你的好话，一旦遇到利益关系，暗地里却无情的咒骂你，看着正直如君子，却很少人知道他们虚伪的一面，这样的人我们称之为两面人，这种心口不一，唯利是图，喜欢玩阴招的人不值得深交。</p><p>人都是有缺点的，这很正常，但是有些东西我们要用理智去看待，那些喜欢在人前笑，背后捅刀子的人，早晚有一天会成为你的敌人，所以面对这种人，还是趁早绝交吧。</p><p>人生寄语：人生很宝贵，交友须谨慎，不管是面对陌生人还是熟人，我们都应该保持一份警惕，毕竟朋友是一辈子的事情，如果和“心术不正”的人做朋友，早晚会出事情，特别是遇到上面三种特征的人，就要开始注意了。</p><p>接触什么样的人就有什么圈子，就有什么样的格局！<br>&nbsp;</p><p>你圈子里的人决定你的命运</p><p>不虚度岁月<br>&nbsp;</p><p>不蹉跎时光<br>&nbsp;</p><p>每一天都有滋有味<br>&nbsp;</p><p>生活自然精彩纷呈</p><p>当你停止抱怨，你的好运就开始了</p><p>人有抱怨的习惯，却不知道这个习惯会给自己带来许多的麻烦。<br>&nbsp;</p><p>夫妻相互抱怨，能永久恩爱吗？<br>&nbsp;</p><p>儿女对父母抱怨，父母会甘心情愿付出爱吗？<br>&nbsp;</p><p>下属对上司抱怨，上司会欣赏这样的人吗？<br>&nbsp;</p><p>过去的帝王，对于抱怨的臣子不但冷落以对，臣子甚至还可能招来杀身之祸。<br>&nbsp;</p><p>古人云:任劳是消业，任怨是积福，所以当一个人做事不辞劳苦，不怕别人埋怨，也没有任何抱怨的时候，就是在消业积福，好运也就悄悄的向你而来。<br>&nbsp;</p><p>那么，人为什么不要抱怨呢?抱怨之害，尤有甚者，列举如下：<br>&nbsp;</p><p>1抱怨是丧志之始！<br>&nbsp;</p><p>人一旦心中满怀怨恨，所谓怨天尤人，总觉得世间不公平，觉得天下人都对不起自己，这就是人生危险的讯号。<br>&nbsp;</p><p>因为你对社会的热情不够，对人生的际遇认识不清，对自己的付出心有不甘，对自己的获得有所不满，因此忿忿不平，怀忧丧志，人生从此一蹶不振。<br>&nbsp;</p><p>其实，这个社会必定先要有所付出，才能赢得相对的收入；你只是抱怨付出，怎么会有好的结果呢？<br>&nbsp;</p><p>2抱怨是结仇之源<br>&nbsp;</p><p>抱怨绝对不能获得欢喜，你抱怨人家一分，别人回给你的可能是加倍的排斥。<br>&nbsp;</p><p>合伙人本来是共同打拼，但你总抱怨对方的不足，难道对方就会满意、钦佩你吗？<br>&nbsp;</p><p>语云“敬人者，人恒敬之”，相同的，“怨人者，人恒怨之”，“管鲍之交”就是说鲍叔牙不介意管仲，在钱财、事业上没有半句怨言，所以两人才能相知相惜，才会有好的结果。<br>&nbsp;</p><p>3抱怨是败德之行<br>&nbsp;</p><p>人一旦有了抱怨，情绪一定非常恶劣，就借酒浇愁。有的人甚至“一不做，二不休”，因为对家庭抱怨多，他干脆不回家，整日徘徊在酒廊舞厅里；<br>&nbsp;</p><p>因为对公司有很多不满，他可以请假出游，甚至泄露机密，使公司受到损失。抱怨的结果，可能对方损失有限，但自己则有更大的败德之行。<br>&nbsp;</p><p>例如抱怨父母者，成了不孝儿女；抱怨朋友者，最后反目成仇；<br>&nbsp;</p><p>抱怨同事者，明争暗斗。种种败德的行为，都由于抱怨而产生，殊为可怕。<br>&nbsp;</p><p>4抱怨是造业之因<br>&nbsp;</p><p>世上很多的打斗、毁坏、嗔杀等行为，都是因为抱怨而起，所以抱怨是造业之因。一个人如果时时心存善念，纵使受了委屈，被人欺负，只要自己有修养，稍加忍耐，也就过去了。<br>&nbsp;</p><p>假如感到利益不均，或者为人所侵占，也不能为了虚浮的财利，造下难以弥补的冤仇、业报，最后受害最大的还是自己。因此，一个人一旦心中有了抱怨的念头，自己应该立刻有所警觉，自己要懂得回心反省。<br>&nbsp;</p><p>老话说:怨和气是相通的，人一怨就有气，越气越怨，越怨越气，当一个人满身怨气的时候，怎能与天地的祥和之气对接呢，所以，人一怨福气就没有了。<br>&nbsp;</p><p>当你停止抱怨，你的好运也就开始了！</p><p><br><br>作者：一枚老僧<br>链接：https://www.jianshu.com/p/14804870a546<br>来源：简书<br>著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</p>', '/uploads/page/20200921/db383c687690f31f144783a750bc4906.jpg', 1, '[1]', 4, '2020-09-21 18:41:51', 'now', 1, 23, 0, 0, NULL, NULL, 1, 1, '2020-09-21 18:20:45', '2020-09-21 16:54:44');
INSERT INTO `page` VALUES (24, 3, '人生建议：不要和总是打压你的人在一起', '之前有个同事，性格急躁。公司安排给他一个刚大学毕业的新人，那名新人每日跟着他，他教新人根本没有耐心，总是三言两语之后，就开始不耐烦，辱骂新人太笨，怎么什么都学不会，结果，3个月之后，同批的其它新员工，都开始能够独立工作，而唯独这位新人唯唯诺诺，前怕狼后怕虎的，总担心自己出错，再被师傅挨骂。', '<p>人生建议：不要和总是打压你的人在一起</p><p>一、一人若长期被打压，他会变得不自信。</p><p>之前有个同事，性格急躁。公司安排给他一个刚大学毕业的新人，那名新人每日跟着他，他教新人根本没有耐心，总是三言两语之后，就开始不耐烦，辱骂新人太笨，怎么什么都学不会，结果，3个月之后，同批的其它新员工，都开始能够独立工作，而唯独这位新人唯唯诺诺，前怕狼后怕虎的，总担心自己出错，再被师傅挨骂。</p><p>二、一个人若是经常被打压，得不到鼓励，那么他就会开始怀疑自己的价值和能力。<br>&nbsp;</p><p>公司新进一名助理，其实挺优秀的，但由于所跟领导过于严格，不管她做的有多好，她总是得不到表扬和鼓励不说，还总被领导鸡蛋里挑骨头，想办法打击一番，长期以往，我发现这位同事，总是在公司一个人的时候，偷偷流泪，怀疑自己是不是真的不行。</p><p>三、有些人对别人打压，也许只是为了满足自己的自我优越感，但殊不知，他却有可能毁了别人的一生。</p><p>我小学同学，班里有个不怎么爱说话小男孩，学习一般，课余时间老师和同学都爱拿他开玩笑调侃，说他这也不行那也不行，当时所有人只是为了图个乐子，没想到这个小孩，后来越来越抑郁，最终因为交流障碍，而辍了学。</p><p>四、恋人间的打压，会让一个人变得自卑。</p><p>比如，你穿一件衣服，朋友说你不好看，你看个剧，别人说你没品位等等，当你长期出于这样的抨击中，你就会渐渐的开始怀疑自己的品味，或者自己是不是真的很差。</p><p>五、打压别人，其实是一种不尊重人的表现，所以朋友之间，偶尔开开玩笑可以，长期打压别人，就是对当事人的不尊重。</p><p>一切的不快乐，不是因为缺钱，就是因为缺爱。所以爱你的人是一定舍不得打压你的，长期打压你的人，一定是不爱你的人。 ​​​</p><p>人与人之间，互相尊重是最起码的礼貌，生活应该是温柔而美好的，所以，远离让你不开心的人和事。</p><p>那些你不管说啥，都要夹枪带棒贬你一番的人，不管是他自认为的幽默，还是真的情商欠费，不舒服就远离她。<br>&nbsp;</p><p>因为生活已经很难，我们需要正能量，我们需要快乐和鼓励。</p><p>&nbsp;</p><p>76人点赞</p><p>&nbsp;</p><p><a href=\"/nb/22883494\">记忆碎片</a></p><p>&nbsp;</p><p><br><br>作者：一枚老僧<br>链接：https://www.jianshu.com/p/243b5344997b<br>来源：简书<br>著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</p>', '/uploads/page/20200921/d8d6964c23c0f77f8d39521bf2fda427.jpg', 1, '[1]', 2, '2020-09-21 18:40:52', 'now', 1, 64, 0, 0, NULL, NULL, 1, 1, '2020-09-21 18:22:40', '2020-09-21 16:54:22');
INSERT INTO `page` VALUES (25, 1, '社会大学让每个人都清醒', '早晨醒来看头条，看了涂磊节目里一对母子上台讲述曾经学习优秀的儿子毕业五六年一事无成，而且还欠了一些债务。\r\n母亲讲述了儿子毕业后频繁换工作，本来学的是金融专业，毕业后去了银行上班，因为午休时在大厅躺着休息，被行长责备辞退。', '<p>早晨醒来看头条，看了涂磊节目里一对母子上台讲述曾经学习优秀的儿子毕业五六年一事无成，而且还欠了一些债务。</p><p>母亲讲述了儿子毕业后频繁换工作，本来学的是金融专业，毕业后去了银行上班，因为午休时在大厅躺着休息，被行长责备辞退。</p><p>后来又去了通讯公司，推销时不顺利，又辞职。</p><p>再后来去了汽车修理店，做起来打工族，坚持八个月又走了，</p><p>接着做过奶茶店，外卖店，赔了十多万，最近在做后厨，一个月三千还债中。</p><p>一个文质彬彬的男孩，曾经上学时是家族的骄傲，如今成了母亲嘴里的废物。</p><p>还不如没有上大学的男孩，他表弟开了一家汽车美容店，今年给父母买了一百多平的房子。</p><p>现在真的有很多大学毕业的人，混的还不如没上大学的人。</p><p>上学真的不是每个人上升的途径，再说大学四年没有很好的专业对接，其实就是浪费孩子们的青春和宝贵时间。</p><p>有很多家长感慨，读书的时间太长，耽误了孩子学技能最关键的几年时间。</p><p>如今是一个务实的社会，而有的大学还像空中楼阁，象牙塔，当毕业走入现实，就像从云端跌入谷底。</p><p>没有接地气的教育，就不是好的教育。</p><p>高中毕业，就已经在校十二年，十二年没有学到一技之长，高中毕业就等于多认识几个字，到社会上从新学习生存技能。</p><p>如今应该调查一下，如今的大学生几年以后都去了哪？做了什么工作，工作家庭如果？和自己所学专业有关吗？他们如今都是大学的获利者吗？</p><p>听一个博主说，“为什么中国学校不教孩子如何挣钱，除了教授所谓知识，从来不教孩子们如何挣钱生存，是因为老师都不知道如何挣钱。”</p><p>他的话听着可笑，但是也有一定的道理。</p><p>老师除了开资没有挣钱技能，怎么教育孩子如何挣钱如何攒钱，如何获得财富自由。</p><p>在这方面家长和老师都是欠缺的，所以也就没有教育意识。</p><p>不像国外，有的从七八岁的孩子都开始教育他们如果挣钱理财，那才是真正的本领。</p><p>学校是一个单纯的地方，好像和社会脱节。</p><p>大学毕业后进入社会，那才是真正的教育，他们走出单纯的环境，进入复杂的社会，不成长你就被淘汰。</p><p>社会大学才是一所最牛逼的大学。</p><p>每一个走出象牙塔的学生，在社会大学里才能练就一身生存本领。</p><p><br><br>作者：在听Yellow<br>链接：https://www.jianshu.com/p/2e857c61ad99<br>来源：简书<br>著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</p>', '/uploads/page/20200921/5504d25bd5d8c4fe2e6c309b51f766c1.jpg', 1, '[28]', 0, '2020-09-21 18:23:30', 'now', 1, 34, 0, 0, NULL, NULL, 1, 1, '2020-09-21 18:23:30', '2020-09-21 16:54:38');
INSERT INTO `page` VALUES (26, 3, '美军没来，解放军却连续2天操演 民进党当局纳闷了？', '前不久，解放军连续2天在台湾岛西南方进行海空演训，这一动作受到台湾岛内媒体广泛关注。据台媒报道显示，此次操演区域约有1/3在台西南角所谓“防空识别区”内，参演机舰距台最近约90海里。', '<p>【两岸快评第947期】</p>\r\n<figure class=\"image\"><img src=\"https://p3-tt.byteimg.com/origin/pgc-image/SAdabDHAeLrZQz?from=pc\" alt=\"美军没来，解放军却连续2天操演 民进党当局纳闷了？\" /></figure>\r\n<p>前不久，解放军连续2天在台湾岛西南方进行海空演训，这一动作受到台湾岛内媒体广泛关注。据台媒报道显示，此次操演区域约有1/3在台西南角所谓&ldquo;防空识别区&rdquo;内，参演机舰距台最近约90海里。</p>\r\n<p>解放军这一举动，让民进党当局&ldquo;躁动不已&rdquo;。民进党当局防务主管部门与外事主管部门日前接连针对这一情况召开记者会。其中，台湾防务部门声称，美军机舰这两天未在附近活动，解放军军演明显针对台湾。</p>\r\n<p>按照台湾军方的逻辑，似乎解放军此前种种动作针对的均是美军，与台湾方面没多大关系。这种思路本身就存在本末倒置的问题。<strong>要知道，真正触发两岸紧张情势的，正是如今执政的民进党当局。</strong></p>\r\n<p>民进党自上台以来，一直通过各种手段推动&ldquo;渐进台独&rdquo;，尤其蔡英文第二任期后，随着外部势力干涉力度升级，民进党当局在军事领域频繁与美军唱和，俨然以美国&ldquo;盟友&rdquo;自居，单方面改变台海区域和平稳定局面。</p>\r\n<p><strong>在两岸关系因民进党当局拒不承认&ldquo;九二共识&rdquo;而丧失共同政治基础的背景下，台军的每一次军购、演训、导弹试射等活动，都有可能成为擦枪走火的导火索。</strong></p>\r\n<p>台湾防务部门在记者会上对解放军演训情况进行了介绍，称解放军海、空军接连两天，以苏-30、歼-10及运-8等多型主战及辅战机种，配合海军各型船舰，采多兵力、多架次、多艘次，进入台所谓&ldquo;防空识别区&rdquo;内西南海、空域实施海空联合演训，参演机舰距台最近约90海里。</p>\r\n<p>台媒对此分析，<strong>这个距离带给台军的处置压力可想而知。从台两部门极罕见先后开临时记者会动作来看，事态并不寻常。</strong></p>\r\n<p>关于解放军海空军力战备巡航，中国人民解放军东部战区新闻发言人张春晖曾明确表示，台湾及其附属岛屿是中国领土神圣不可分割的一部分，中国军队战备巡航完全正当合法，是针对当前台海安全形势和维护国家主权需要采取的必要行动。</p>\r\n<p>针对民进党当局企图以武获&ldquo;独&rdquo;、以武拒统，国台办发言人马晓光强调，以武拒统，死路一条。</p>\r\n<p>民进党当局应该清醒的认识到，自己甘做美国走狗没人拦着，但要想把中国的领土分裂出去，必将受到包括台湾同胞在内的所有中国人民的坚决反对。解放军有决心、有能力挫败一切&ldquo;台独&rdquo;分裂活动。（文/关其行）</p>', '/uploads/page/20200921/30abfd1844b131419aaec094c21595c7.jpg', 1, '[3, 6]', 6, '2020-09-23 16:20:50', 'now', 1, 783, 0, 1, NULL, NULL, 1, 1, '2020-09-21 18:24:32', '2020-09-23 10:21:59');
INSERT INTO `page` VALUES (27, 3, '孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”', '《隐秘的角落》都播完几个月了，张东升将岳父母推下山的阴影却始终笼罩在人的心头挥之不去。\r\n每当想起这个画面，总是让人忍不住瑟瑟发抖。\r\n可论起恐怖程度，现实生活绝不输电视剧。', '<p>《隐秘的角落》都播完几个月了，张东升将岳父母推下山的阴影却始终笼罩在人的心头挥之不去。</p><p>&nbsp;</p><p>每当想起这个画面，总是让人忍不住瑟瑟发抖。</p><p>&nbsp;</p><p><strong>可论起恐怖程度，现实生活绝不输电视剧。</strong></p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/9eab419c8a144b42b1821d4f0f974c91?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>2019年6月9日，怀孕3个月的王女士与其丈夫前往泰国帕登国家公园的山上看日出。</p><p>&nbsp;</p><p>登山前，丈夫特意制止她携带手机上山，还以带她去看三千年前的古人类壁画为由，将她带到了悬崖边。</p><p>&nbsp;</p><p>丈夫从身后环抱着她深情亲吻，孰料这浓情蜜意在下一秒就变成了杀人的刀——</p><p>&nbsp;</p><p>他将她一把推下了悬崖，并恶狠狠地叫嚣着：“你去死吧！”</p><figure class=\"image\"><img src=\"https://p1-tt.byteimg.com/origin/pgc-image/787e7080d66d458a90bf68d2b987b6d0?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>随后，他在山崖边坐了40分钟，以为妻子死透了才径直离开。</p><p>&nbsp;</p><p><strong>可他没有想到的是，悬崖下一棵离地10米高的树，让妻子捡回了一条命。</strong></p><p>&nbsp;</p><p>坠崖451天后，从地狱回来的王女士复盘了自己被丈夫推下悬崖的全过程，我们才发现：</p><p>&nbsp;</p><p>原来这场精心策划的婚姻，从一开始就是为了要她的命。</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/4cabf1bfbbf740a0a2cd66dca9179e0f?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>来自江苏南京的王女士，是一名非常优秀又独立的女性。</p><p>&nbsp;</p><p>早在27岁前，就已经通过自己的奋斗，在泰国曼谷有了房产和公司，并在曼谷华人圈小有名气。</p><p>&nbsp;</p><p>2017年5月的一天，在一次朋友聚会上，一名叫做俞某东的男子主动向她搭讪并索要微信。</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/ebccd814000149ee8d3aa7aea87bc76d?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>谨慎的王女士起初并不想搭理他，可俞某东几次三番提出加好友的邀请，碍于朋友的面子她终于同意。</p><p>&nbsp;</p><p>原本以为只是客套地加个好友，以后也不会有什么联系，没想到俞某东三天两头给她发信息搭讪。</p><p>&nbsp;</p><p>忙于工作的王女士很少给他回应，可聪明的俞某东很快就掌握了她的作息习惯——</p><p>&nbsp;</p><p>正在学习泰语的王女士每周都要去上课，俞某东便趁此机会去接送她上下学。</p><p>&nbsp;</p><p>俞某东的陪伴，对长期异国他乡的王女士来说实在是不小的慰藉。</p><p>&nbsp;</p><p><strong>再加上整个过程中，俞某东都没有什么逾矩的行为，很是绅士得体，王女士对他也渐渐有了好感。</strong></p><figure class=\"image\"><img src=\"https://p3-tt.byteimg.com/origin/pgc-image/a739ba69e47a4e668fdeb6b7b6d53d69?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>一段时间后，俞某东写了一篇很长的小作文向王女士表白，并提出二人以结婚为前提进行交往。</p><p>&nbsp;</p><p>事业有成的王女士觉得自己也到了适婚年龄，便答应了他的表白。</p><p>&nbsp;</p><p>正式交往后，王女士越发觉得俞某东是个非常可靠的人。</p><p>&nbsp;</p><p>他生活态度非常阳光积极，每周都坚持健身，也很勤劳，整个人都充满了向上的正能量。</p><p>&nbsp;</p><p>王女士心想，自己终于觅得良人了。</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/b34a6340b36744d6847737e27ce937ae?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>只是当时的她并不知道，俞某东营造出来的一切都是假象——</p><p>&nbsp;</p><p>他早就把她的朋友圈翻了一个遍，摸透了她的喜好精准下手。</p><p>&nbsp;</p><p><strong>交往20多天后，俞某东就开始想尽一切办法提出结婚：</strong></p><p>&nbsp;</p><blockquote><p>我们结婚好不好？你嫁给我好不好？</p><p>如果对的人出现了，早和晚是没有关系的；</p><p>我们先领证，先进入婚姻；</p><p>你给我一点时间，我来奋斗，很快我会给你的亲朋好友一个满意的答复，我会向他们证明，你勇敢地跟我携手进入婚姻，你选对人了……</p></blockquote><p>&nbsp;</p><p><strong>尽管王女士以“太仓促”为由拒绝过多次，却还是禁不住对方的软磨硬泡。</strong></p><figure class=\"image\"><img src=\"https://p3-tt.byteimg.com/origin/pgc-image/b664adb2d2414bb78b2e21a72235e566?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>一个月后，她终于答应了俞某东的求婚。</p><p>&nbsp;</p><p>而这场闪婚，也成了她噩梦的开始。</p><figure class=\"image\"><img src=\"https://p3-tt.byteimg.com/origin/pgc-image/9b0f75147f8845b7a2bd1774b3f9c1d1?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>在俞某东向王女士求婚期间，他就主动坦白了自己曾因盗窃抢劫而入狱的经历。</p><p>&nbsp;</p><p>但他说，那时的自己年轻不懂事，是被朋友带偏的，如今的他只想洗心革面，给王女士一个美好的未来。</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/45229fa3edc141f18025d35a01aaa035?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>王女士觉得，这个男人还算真诚。</p><p>&nbsp;</p><p>加之整个交往过程中他都变现得彬彬有礼、可圈可点，也真的相信他已经改过自新。</p><p>&nbsp;</p><p>2017年7月15日，俞某东以回家探亲为由将王女士带回了国，连哄带骗地与她领了结婚证。</p><p>&nbsp;</p><p>从相识到步入婚姻，仅仅用了两个月的时间。</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/bfb18818357a411daf2f3f1dfffd6e48?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>婚后生活，也跟俞某东当初向王女士承诺的完全不一样。</p><p>&nbsp;</p><p><strong>他很快就暴露了自己真实的一面。</strong></p><p>&nbsp;</p><p>不再维持自律向上的形象，甚至在王女士生病的时候都懒得关心一下。</p><p>&nbsp;</p><p>才刚新婚两个月，两人就陷入了不断的争吵中，而问题的核心也永远只有一个：</p><p>&nbsp;</p><p>俞某东不断向王女士索要钱财，要求她替他还赌债。</p><p>&nbsp;</p><p>一旦王女士拒绝给钱，他就以离婚分割财产为由对她进行威胁。</p><figure class=\"image\"><img src=\"https://p3-tt.byteimg.com/origin/pgc-image/0e1c2cb3933948d0bc3659aca1dec9d4?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>直到这时，她才发现，原来自己根本不曾了解过眼前的这个男人。</p><p>&nbsp;</p><p><strong>他嗜赌成性，爱玩游戏，还欠下了一屁股赌债，对家庭更是没有一点责任感。</strong></p><p>&nbsp;</p><p>自己一次又一次地替他还赌债，换来的却是他的变本加厉。</p><p>&nbsp;</p><p>很快，王女士发现自己怀孕了。</p><p>&nbsp;</p><p>她发现俞某东的态度，也随自己的怀孕发生了明显的变化。</p><p>&nbsp;</p><p>她想，也许自己可以通过孩子，去改变、感化俞某东。</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/0b9e07110bb3418c8d6cc15929f1ec1c?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>为了不让自己在这段婚姻中的投入打水漂，也为了腹中尚未出世的孩子，王女士决定再给他一次机会。</p><p>&nbsp;</p><p><strong>她答应帮俞某东偿还一笔几百万的债务，“债只能帮忙还一半，剩下的你要通过自己的劳动还”。</strong></p><p>&nbsp;</p><p>王女士以为这样就能让他慢慢戒掉嗜赌的坏习惯。</p><p>&nbsp;</p><p>殊不知，江山易改本性难移，习惯了索取的俞某东早已有了自己的如意算盘：</p><p>&nbsp;</p><p>只要王女士一死，她的所有财产就都是自己的了。</p><p>&nbsp;</p><p><strong>没过多久，俞某东就为王女士买了一份意外保险，而受益人便是他自己。</strong></p><p>&nbsp;</p><p><strong>紧接着，她就被他推下了山崖。</strong></p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/d090258b1bea4181814341dddbe6c6f0?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/f133811e63044409bf323cde114d0a9d?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>都说婚姻是爱情的坟墓。</p><p>&nbsp;</p><p>但如今，它不仅成为了王女士爱情的坟墓，也成为了她孩子的坟墓，并且差点掩埋了她。</p><p>&nbsp;</p><p>而这个早就挖好的坑，她原本有无数次机会可以避开。</p><p>&nbsp;</p><p><strong>第一次可以避开的机会，在她刚与俞某东相识时。</strong></p><p>&nbsp;</p><p>那时的他说着让王女士亲切的家乡话，有7、8分的相似，但一听就不是本地人，她最初就曾起过疑心：</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/be5082e854c04a87986deb4d32a6ec52?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p><strong>第二次机会，是俞某东为了博取她的信任，主动坦白了自己曾入狱的经历。</strong></p><p>&nbsp;</p><p>人非圣贤孰能无过，但是过错也分大小，也足以暴露一个人的善恶本性，在这样的大是大非面前，千万不要以为自己是可以拯救世界的超级英雄。</p><p>&nbsp;</p><p>不要在垃圾堆里捡男友，更不要试图去改变一坨垃圾。</p><p>&nbsp;</p><p><strong>因为，浪子不会回头，只会回头吃肉喝血：</strong></p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://p1-tt.byteimg.com/origin/pgc-image/995b99b978a14019ba5b833ec7bfdd9c?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p><strong>第三次机会，是俞某东开始频繁提出结婚的请求。</strong></p><p>&nbsp;</p><p>事业有成什么都不缺的王女士，因为自己“到了年纪”，碍于社会的眼光和俞某东执着的追求，一时脑热糊涂结了婚。</p><p>&nbsp;</p><p>可对现实中的大多数姑娘来说，所谓的「闪婚」真的没有多少可取之处。</p><p>&nbsp;</p><p><strong>婚姻对很多人来说是一辈子的事，它不是消耗品，更不可能是日抛型。</strong></p><p>&nbsp;</p><p><strong>两个人在一起生活朝夕相处，无论是从人品、三观、道德，还是习惯、欲望、追求等，都需要对对方有一个充分认知的过程。</strong></p><p>&nbsp;</p><p>在决定嫁给俞某东前，王女士不仅没有摸透这个人的真正习性，更是对他的家庭背景一无所知：</p><p>&nbsp;</p><blockquote><p>“除了他自身有坐牢的前科以及百万债务之外，他的父亲年轻时也一直没有工作，靠他母亲的钱生活。”</p></blockquote><p>&nbsp;</p><p>在俞某东的犯罪行为曝光后，其母亲还多次威胁王女士撤诉：</p><p>&nbsp;</p><p>“你又没死，凭什么报警抓我儿子？”</p><p>&nbsp;</p><p><strong>甚至还妄图为他做无罪辩护，声称是儿子身上的恶魔纹身驱使他杀人：</strong></p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/43b6118b60e743e5840a5b2e5b671497?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p><strong>第四次机会，在俞某东婚后暴露出真实一面时，王女士却犹犹豫豫不肯离婚。</strong></p><p>&nbsp;</p><p><i><strong>“我就像那个赌桌上的人，下不来了。”</strong></i></p><p>&nbsp;</p><p>然而，一段错误的婚姻不可怕，浪费时间精力金钱也不可怕，可怕的是不懂得及时止损。</p><p>&nbsp;</p><p>继续与烂人纠缠，只会失去的越来越多：</p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://p1-tt.byteimg.com/origin/pgc-image/9c6f03d95bd7475bb05a539c41a13c8a?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p><strong>第五次被王女士错过的机会，最令人又气又恨。</strong></p><p>&nbsp;</p><p><strong>在俞某东为她买人身意外险时，她就曾质疑过为什么受益人是他，最后却出于信任不了了之了：</strong></p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://p1-tt.byteimg.com/origin/pgc-image/03d40795442842e8a2e71d316a36550a?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>在仔细复盘了俞某东与自己相识相处的整个过程后，王女士悔恨不已。</p><p>&nbsp;</p><p>我们常说：结婚要慢，离婚要快。</p><p>&nbsp;</p><p>这是对所有人都适用的一句婚姻忠言。</p><p>&nbsp;</p><p><strong>无论哪种情况哪种境遇，婚前不够了解，婚后有的是后悔。</strong></p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/76706630d66d4c33bfbc0692509a8518?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>遇到这样吃人不吐骨头的渣男，王女士是不幸的。</p><p>&nbsp;</p><p>可同时她又足够幸运。</p><p>&nbsp;</p><p>她幸运地在坠落山崖时掉到了树上捡回一条命，又幸运地被周遭游客发现救助。</p><p>&nbsp;</p><p>更幸运的是她的孩子也一直保护着她，没有在妈妈受重伤时选择离开，让她因血崩而丧命。</p><p>&nbsp;</p><p><strong>然而，这世间又有多少女性能够如她这般幸运呢？</strong></p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/18d44415f22a4831a130fc5d70579b29?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>最近这段时间，杀妻、杀女友案频繁发生，在感情婚姻中的女性受害者数不胜数。</p><p>&nbsp;</p><p>每当看到诸如此类的新闻，我们的警惕心只会短暂地提高，然后在自己的感情面前重蹈覆辙。</p><p>&nbsp;</p><p>爱情是美好的，婚姻也是充满希望的。</p><p>&nbsp;</p><p><strong>我们不希望女孩们因为极少数人的恶，而对爱情婚姻失去信心，却也不得不再次提醒大家一定要小心警惕。</strong></p><p>&nbsp;</p><p>之前曾多次安利给大家的律师<strong>@吴杰臻</strong>教你自保的20条婚姻忠告，希望女孩们一定要牢记心中。</p><p>&nbsp;</p><p><strong>结婚前一定“不要着急结婚”、“要查对方的征信”、“查看对方的体检报告”等：</strong></p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/6040c627dfef40a5bf679e2a390da57a?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure><p>&nbsp;</p><p>&lt;上下滑动图片查看全文&gt;</p><p>&nbsp;</p><p><strong>结婚后需要注意的也有很多。</strong></p><p>&nbsp;</p><p><strong>“取消手机指纹开机，设置锁屏密码和sim卡的PIN码”，以防止对方背着你借贷等：</strong></p><p>&nbsp;</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/8a932669f4cc46608ea67b369b89882d?from=pc\" alt=\"孕妇坠崖451天后：“为了要我的命，他从开始就计划好了一切”\"></figure>', '/uploads/page/20200921/f7b9bfca10432c02cb9ca815266daf68.jpeg', 1, '[27, 6, 28]', 4, '2020-09-21 22:27:40', 'now', 1, 52, 0, 0, NULL, NULL, 1, 1, '2020-09-21 18:26:06', '2020-09-22 09:21:37');
INSERT INTO `page` VALUES (28, 3, '男子网恋半年花了12万，因彩礼分手 谁料“女友”长这样', '“如今我算是彻底想明白了，不过就是舍不得出最后这八千块钱而已……谢谢你来到过我的世界……”一段长长的分手留言后，刘某被女友静儿拉黑了。收到这段分手留言前，刘某与静儿本计划着结婚大事，但彩礼成了两人感情的绊脚石。', '<blockquote><p>“如今我算是彻底想明白了，不过就是舍不得出最后这八千块钱而已……谢谢你来到过我的世界……”一段长长的分手留言后，刘某被女友静儿拉黑了。</p><p>收到这段分手留言前，刘某与静儿本计划着结婚大事，但彩礼成了两人感情的绊脚石。两人发生争吵，刘某和静儿的母亲也闹了不愉快。</p><p>两人相识于网络，在一起仅半年有余，<strong>日常里两人互称对方“老公”“老婆”，不过直到分手也没有见过一面。而在这半年里，刘某却为静儿前后转账12万余元。</strong></p><p>被静儿拉黑之后，刘某以为女友“失踪”了，甚至向警方报警。不想，最后的侦查结果出人意料——他喜爱的静儿实际上是一个专门从事电信诈骗的犯罪嫌疑人，其背后是一个分工明确的诈骗团伙。</p></blockquote><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/SB7ElOyGG3Tn46?from=pc\" alt=\"男子网恋半年花了12万，因彩礼分手 谁料“女友”长这样\"></figure><p>↑与刘某聊天的“女友”，文某某被抓获</p><p><strong>小伙报警求助：网恋女友不见了</strong></p><p>“警官，我女朋友不见了，麻烦帮忙找一下……”今年1月中旬，刘某急匆匆到成都青白江龙王派出所报警。在刘某的讲述中，他和女友静儿分手了，自己一直无法联系上对方，担心对方发生意外。</p><p>恋爱闹分手，原本谈不上什么警情。但在与刘某更进一步的了解中，警方发现，刘某恋爱的女友可能并非真的在与其恋爱，更像是有所目的，对其进行诈骗。</p><p>警方介绍，在恋爱过程中，刘某与“女友”静儿相识仅仅半年多时间，期间对方多次向刘某索要钱财，<strong>刘某有记录的各类转账多达12万余元，且两人一直没有见过面，而这次分手也正是因为钱的问题。</strong></p><p>“这在目前也算是一种较为常见的诈骗手法，所谓的‘女友’实际上很可能是诈骗团伙。”警方判定，刘某很大程度上遭遇了电信诈骗。</p><p><strong>网恋半年 女友常生病并开口要钱</strong></p><p>据介绍，刘某在青白江一家食品加工公司上班，他和“女友”静儿是在2019年5月底通过一家婚恋网站相识的。</p><p>刘某介绍，对方叫文静，在成都一家公司上班，在一段简单交流后，觉得不错，便加了微信继续联系。通过一段时间的了解后，两人熟络起来，感情也逐渐升温。</p><p>文静对刘某很上心，不仅认真了解刘某的基本情况，对其也随时嘘寒问暖。两人互换了照片，不时视频聊天。面对如此知冷知热的女性朋友，刘某动了心，很快确定了恋爱关系。</p><p>“她年轻又可爱。”刘某这样评价对方的印象。两人的称谓也发生了变化，相互叫对方为“老公”“老婆”。但两人却一直没在现实里见过面。</p><p>刘某很享受这段恋情，但是静儿似乎常常生病，并向刘某要钱，几百上千。静儿也会不时喜欢上一些衣服，希望刘某能够为其购买。因为工作原因不能经常在一起，刘某毫不犹豫地一一答应了。</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/SB7ElQB4i2iydx?from=pc\" alt=\"男子网恋半年花了12万，因彩礼分手 谁料“女友”长这样\"></figure><p>↑聊天记录显示，“女友”多次要钱</p><p>半年左右，两人开始谈婚论嫁，静儿的母亲也加入了两人的聊天。看婚纱，看婚戒，一切似乎顺利。不过，彩礼钱却让这段感情走向了破裂。因为前后已经支出了不少钱，刘某不愿意再给最后的8000元。</p><p>而这导致最终分手。“如今我算是彻底想明白了，不过就是舍不得出最后这八千块钱而已……谢谢你来到过我的世界……”一段长长的分手留言后，刘某被女友静儿拉黑了。而此时刘某已经向女友前后转账了12余万元。</p><p><strong>“女友”实为大汉 背后团伙分工明确</strong></p><p>接到刘某的求助后，警方成立了专案组进行侦查，终于掌握了刘某“女友”的行动轨迹，确定其在山西吕梁活动。</p><p>今年7月、8月，青白江警方在山西吕梁、成都等地先后将涉案的嫌疑人王某某、文某某、文某挡获。经审查，三人对利用网络平台以谈恋爱为由骗取刘某12余万元的违法犯罪事实供认不讳。</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/SB7ElQj1d98Hge?from=pc\" alt=\"男子网恋半年花了12万，因彩礼分手 谁料“女友”长这样\"></figure><p>警方介绍，三人在该案件中扮演着不同角色。王某作为组织者主要负责场地租赁、键盘手招聘、目标对象选取等工作；文某某作为键盘手主要负责和受害者聊天，并以各种理由套取对方钱财；文某作为唯一的女性，则主要负责视频聊天以及线下见面工作。</p><p>“也就是说除开视频和线下见面博取信任外，大部分的聊天都是男性嫌疑人在和刘某对话。”办案民警介绍。</p><p>目前，犯罪嫌疑人已被依法采取刑事强制措施，案件正在进一步办理之中。警方提示，网恋有风险，不要轻信网络信息，不透露个人隐私，不转账汇款。</p><p>红星新闻记者 杜玉全 警方供图</p>', '/uploads/page/20200921/60da0ed58a066f4c1262dfc765fa2675.jpg', 1, '[27, 4, 10]', 2, '2020-09-21 18:28:28', 'now', 1, 34, 0, 0, NULL, NULL, 1, 1, '2020-09-21 18:28:28', '2020-09-22 03:20:25');
INSERT INTO `page` VALUES (29, 1, '内行看门道：解放军靠近台湾的18架飞机是精心挑选，且有玄机的', '这大概是自1979年两岸关系缓和以来，台湾海峡局势最为紧张的一天。根据台湾媒体引述台湾\"空军\"的消息称，19日一大早，解放军空军就出动了多达18架各型飞机，从西南、西部、北部以及西北4个方向靠近台湾。台湾\"空军\"从早上7点开始，在一个多小时的时间里，连续发布22次\"广播驱离\"。而且有细心的人发现，台湾\"空军\"在\"广播驱离\"中使用的字眼已经不再是\"防空识别区\"而是实实在在的\"领空\"。', '<p>这大概是自1979年两岸关系缓和以来，台湾海峡局势最为紧张的一天。根据台湾媒体引述台湾\"空军\"的消息称，19日一大早，解放军空军就出动了多达18架各型飞机，从西南、西部、北部以及西北4个方向靠近台湾。台湾\"空军\"从早上7点开始，在一个多小时的时间里，连续发布22次\"广播驱离\"。而且有细心的人发现，台湾\"空军\"在\"广播驱离\"中使用的字眼已经不再是\"防空识别区\"而是实实在在的\"领空\"。</p><figure class=\"image\"><img src=\"https://p3-tt.byteimg.com/origin/pgc-image/9b58a6e543ff4c048547e78edc6a852b?from=pc\" alt=\"内行看门道：解放军靠近台湾的18架飞机是精心挑选，且有玄机的\"></figure><p>注意，这是实弹，不是模型</p><p>这是个什么概念呢？按照联合国海洋公约的约定，各国可自行划定领海，而领海的宽度在3～12海里之间，最大不能超过12海里。领空则是领海垂直以上、大气层以内的空域。当然大气层以外就不算领空了，否则人造卫星天天运行，那麻烦就大了。台湾虽然不敢公开独立，但是划定自己的所谓\"领空\"也是依照联合国公约的要求，所以台湾的所谓\"领空\"，就是靠近台湾海岸线12海里的空域。12海里有多远？1海里=1852米，12海里=22.224千米，也就是约等于22公里的样子。这么近的距离，飞行员已经足够肉眼看到台湾岛，这大概也是解放军自1949年以来，最靠近台湾本岛的一次。</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/5b68b9b60e76490e9c93c559f345e9f0?from=pc\" alt=\"内行看门道：解放军靠近台湾的18架飞机是精心挑选，且有玄机的\"></figure><p>歼-11掩护轰-6K</p><p>再来看解放军这次靠近台湾所使用的飞机。根据台湾方面的说法，本次解放军一共派遣了18架各型作战飞机靠近台湾岛。其中2架是轰-6型轰炸机、8架歼-16多用途战斗机、4架歼-11战斗机、4架歼-10战斗机。解放军这个排兵布阵方式可以说是非常有门道的，甚至可以说未来哪天，真的武力攻打台湾，解放军空军攻击机群的排兵布阵，大概就是这个模式的扩大版。为什么这么说呢？</p><figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/979a2496ba474d22ae4099b8df37f71a?from=pc\" alt=\"内行看门道：解放军靠近台湾的18架飞机是精心挑选，且有玄机的\"></figure><p>据称有挂载了鹰击-12的轰-6J</p><p>其实只要仔细看解放军的排兵就能明白：2架轰-6轰炸机肯定是携带长剑巡航导弹执行远程打击任务的，4架歼-11和4架歼-10战斗机则负责为整个攻击机群提供制空权掩护，用于拦截对岸可能出现的战斗机。而8架歼-16战斗机的任务大概就比较杂了，由于歼-16本身就是多用途战斗机，该机可以兼顾对空作战和对地、对海作战，因此歼-16战斗机大概率会携带空对地、空对舰导弹，为轰-6担任\"补刀\"的任务。只要歼-16携带射程200公里的KD-88或者鹰击-83K型导弹， 就同样可以在台湾防空导弹的打击半径之外，对台湾各类目标发动精确打击，而且，歼-16还可以同样挂载PL-10/12/14/15等空空导弹，用于协助歼-10、歼-11战斗机执行防空作战任务。未来大陆如果确定武力收台的话，空军派出的攻击机群将会是这次飞机编队的放大版。</p><figure class=\"image\"><img src=\"https://p1-tt.byteimg.com/origin/pgc-image/2aafc57cf1b04d8bb9abb65005883ba9?from=pc\" alt=\"内行看门道：解放军靠近台湾的18架飞机是精心挑选，且有玄机的\"></figure><p>&nbsp;</p><p>2019年12月爆发的新冠疫情如今已经完全席卷全球，曾经号称西方灯塔的世界霸主美国，在疫情之下被打得狼狈不堪，而全球唯独中国，不但最早走出疫情困扰，同时也是唯一第二季度经济正增长的国家，所以中美差距进一步缩小，这让美国人看在眼里、急在心头。因为中国的经济水平和军事力量一旦超越美国，那么美国将彻底失去霸主的地位，这是美国绝对不能容忍的。所以美国最近拼命拉拢日本、韩国、新西兰、澳大利亚等国，企图组建反华的亚洲小北约。而一贯抵抗大陆的台湾，也成为美国争取的对象，近一个多月以来， 美国不断提升和台湾的关系，从军机越境到卫生部长访台，再到17日美国副国务卿克拉奇\"访问\"台湾，甚至还要出席李登辉的葬礼，这无疑已经是公开挑战\"一个中国\"的基本原则。美国的一系列煽风点火的举动，不但让中美关系持续恶化，也把台湾送到了风口浪尖。</p><p>严格来说，由于台湾尚未解放，也就意味着中国的国内革命战争从未真正结束，而海峡两岸之间尽管和平多年，但是本质上依然是内战的双方。所以解放军随时都可以打过海峡去，根本不需要找什么所谓的借口。美国这种盲目怂恿台湾的做法，只能不断激化两岸对立，同时坚定大陆武力解放台湾的决心。之所以用\"解放\"这个词，也是因为收复台湾，也正是国内解放战争的一部分，所以用\"解放\"一词更准确。</p><p>如今解放军无论是在技术装备水平，还是部队规模方面，都已经对台湾构成压倒性优势。尽管美国依然是世界霸主、尽管美军确实有预案要干涉台湾问题，但是台湾问题，美国所要面对的是中国，而在距离中国大陆1000公里以内的地区，美军根本无法赢得战争，这一点在朝鲜和越南已经两次上演，如果美国还想把手持续伸向台湾，解放军不介意第三次给美国一个教训，一个刻骨铭心的教训。</p><p>&nbsp;</p>', '/uploads/page/20200921/3aa482a3862591f58799806582b3c5e3.jpeg', 1, '[27, 2, 10]', 1, '2020-09-21 18:29:07', 'now', 1, 35, 0, 0, NULL, NULL, 1, 1, '2020-09-21 18:29:07', '2020-09-22 03:20:13');
INSERT INTO `page` VALUES (30, 3, '光伏涨价博弈步入“冷静期”：下游豪掷百亿要保供 头部多晶硅企业扩产忙', '前段时间涨涨涨的光伏产业链终于冷静下来，9月各制造端价格趋于平稳。然而平稳之下仍暗流涌动，企业之间既博弈也观望。装机量需求增长之下，产能扩张的中游企业豪掷百亿锁定未来五年的硅料供应，足可见原料紧张。硅料生产企业本身是否扩产，也成为被关注的内容之一。', '<p>前段时间涨涨涨的光伏产业链终于冷静下来，9月各制造端价格趋于平稳。</p>\r\n<p>然而平稳之下仍暗流涌动，企业之间既博弈也观望。装机量需求增长之下，产能扩张的中游企业豪掷百亿锁定未来五年的硅料供应，足可见原料紧张。硅料生产企业本身是否扩产，也成为被关注的内容之一。</p>\r\n<p>9月18日，《每日经济新闻》记者在位于包头市的内蒙古通威高纯晶硅有限公司（以下简称内蒙通威）现场看到，二期项目在筹划中。这意味着国内硅料大厂里，通威成了少有的、在2021年和2022年有大规模扩张的企业。根据通威的规划，2023年要将多晶硅料产能扩大至22万~29万吨/年。</p>\r\n<p>但有业内人士表示，多晶硅料扩产也并非想扩就能扩，也要考虑成本等因素的约束。</p>\r\n<figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/Rzj77qID1LoMZj?from=pc\" alt=\"光伏涨价博弈步入&ldquo;冷静期&rdquo;：下游豪掷百亿要保供 头部多晶硅企业扩产忙\" /></figure>\r\n<p>图片来源：摄图网</p>\r\n<p>&nbsp;</p>\r\n<h2><strong>光伏产业链价格博弈进入冷静期</strong></h2>\r\n<p>&ldquo;现在多晶硅料价格确实是行业内比较关注的话题。&rdquo;另一国内硅料大厂的总经理被问到光伏上游多晶硅料的价格趋势时说道。</p>\r\n<p>此前几年较沉寂的硅料，今年因供需失衡突然大火，一个月超七成的涨幅犹如一匹脱缰野马，拉也拉不住。</p>\r\n<p>最近一段时间，多晶硅料价格总算趋于平稳。同样平稳的还有整个产业链，上一周，特级致密料价格为103元/Kg，价格与上上周持平；单晶158硅片一二线厂商价格分别为3.10元和2.90元每片，价格同样与上上周持平；单晶PERC电池片，价格也与上上周持平&hellip;&hellip;</p>\r\n<p>但价格平稳之下，其实暗流仍在涌动。在包头，一位光伏业内人士就对《每日经济新闻》记者表示：&ldquo;现在上下游还是在价格博弈。&rdquo;</p>\r\n<p>&ldquo;博弈&rdquo;一词必然是今年光伏行业使用最高频的词语，几乎每一个光伏人都把它挂在嘴边。上游硅料企业和它的下游硅片企业博弈，硅片企业又和它下游的电池片企业博弈，电池片企业再和组件博弈，组件企业则与下游电站博弈&hellip;&hellip;</p>\r\n<p>价格博弈最激烈的，是光伏产业链最集中的硅料和硅片环节。新特能源、新疆大全、通威、东方希望、保利协鑫这五家掌握了国内硅料80%的份额，隆基股份和中环股份则拿下了硅片市场的大&ldquo;半壁江山&rdquo;。两方的现状是，硅片企业抱怨硅料涨得高，硅料企业又说硅片企业不肯让利。</p>\r\n<p>这一博弈过程就像经济学模型的古诺寡头竞争&mdash;&mdash;每个企业都想获得生产可能性边界下的最高利润，但竞争约束又只能获得讨价还价后的均衡价格。</p>\r\n<p>当硅料企业想把硅料价格从10万元/吨报到15万元/吨，硅片企业直接摆手：&ldquo;对不起，我承受不了。&rdquo;</p>\r\n<p>当硅片企业想把硅料价格从10万元/吨压到8万元/吨，硅料企业也可以说：&ldquo;对不起，我没货了。&rdquo;</p>\r\n<p>这段时间的价格平稳，可以说是各方达成的价格一致&mdash;&mdash;不过是激烈竞价后的僵持阶段。</p>\r\n<p>中国有色金属工业协会硅业分会分析，从上周开始，多晶硅市场供小于求叠加上游开工率提升和下游需求小幅减少的变量，导致上下游进入更加紧张的博弈期，签单量和签单价均处于僵持阶段，因此市场价格如预期持稳不变。</p>\r\n<p>另一方面，硅料实质性紧缺情况未变。根据硅料和硅片在产企业的生产现状及计划，预计9月份多晶硅供应总量在3.7万~3.8万吨（包括进口量），需求量在3.9万~4万吨，仍有0.1万~0.3万吨的供应缺口。从供需总量来看，市场供小于求的局面尚未扭转。</p>\r\n<p>紧张的硅料供给之下，硅料企业已开足马力生产。</p>\r\n<p>鹿城包头&mdash;&mdash;三国名将吕布故乡，是北方重要的重工业城市，通威股份子公司永祥股份旗下的内蒙通威就坐落于此。它与四川的乐山、云南的保山，共同组成了通威多晶硅料三大生产基地。</p>\r\n<figure class=\"image\"><img src=\"https://p6-tt.byteimg.com/origin/pgc-image/SB7vtHfFDJM12b?from=pc\" alt=\"光伏涨价博弈步入&ldquo;冷静期&rdquo;：下游豪掷百亿要保供 头部多晶硅企业扩产忙\" /></figure>\r\n<p>内蒙古通威高纯晶硅厂区。受访方供图</p>\r\n<p>9月的包头，踩着夏季的尾巴，每天日照时间维持在10个小时左右，这是光伏发电需要的区域&ldquo;禀赋&rdquo;。</p>\r\n<p>&ldquo;装置一直保持满产状态，每个月生产量3000吨左右&hellip;&hellip;&rdquo;永祥股份副总经理兼内蒙通威总经理袁中华告诉《每日经济新闻》记者，这是永祥股份旗下首个外省项目，单线产能达到3万吨，是全球单线产能最大的晶硅企业之一。</p>\r\n<p>&nbsp;</p>\r\n<p>内蒙通威停车场上的光伏发电面板。图片来源：每经记者 胥帅 摄</p>\r\n<p>银白色精馏塔，随处可见的光伏电池面板、自动化操作的还原车间&hellip;&hellip;记者在现场看到，内蒙通威没有过密的劳动力投入，而是以自动化生产代之。公司的中控室，10多名工作人员透过屏幕，观察着硅料生产情况，那里还显示着硅料结构占比、单月生产计划、生产进度等。</p>\r\n<p>&nbsp;</p>\r\n<h2><strong>大单保供频现</strong></h2>\r\n<p>当前，光伏产业正在加快替代化石能源，实现清洁能源革命。有人预计，2025年的非化石能源消费占比将从2019年的15.3%再度提升，到2030年有望达到20%的比重。</p>\r\n<p>此前，有业内人士对《每日经济新闻》记者表示，2020年，全球光伏装机量大约在120GW左右。后疫情时代，光伏将是最有竞争力的能源，2021年，全球光伏装机量有望快速提升到140GW~150GW。预计到2025年，全球光伏年装机量将会超过300GW。</p>\r\n<p>根据国际可再生能源署预测，考虑到装机是逐步增长的，因此，最高峰时期有可能达到1000GW的体量。</p>\r\n<p>1000GW是一个什么概念？袁中华解释道，100GW就已相当于5000万吨石油的能源储备。</p>\r\n<p>与之对应，300GW年装机量也就意味着对多晶硅的年需求量将提升到每年100万吨以上。</p>\r\n<figure class=\"image\"><img src=\"https://p1-tt.byteimg.com/origin/pgc-image/SB7vtMi5S7LXHw?from=pc\" alt=\"光伏涨价博弈步入&ldquo;冷静期&rdquo;：下游豪掷百亿要保供 头部多晶硅企业扩产忙\" /></figure>\r\n<p>破碎后的高纯晶硅硅块。图片来源：每经记者 胥帅 摄</p>\r\n<p>据记者了解到，正是在2019年，国内外多晶硅料企业争先恐后扩产上量。</p>\r\n<p>2018年，全球多晶硅产量为40万吨，中国多晶硅产量为25万吨；2019年，这两项数字分别为51万吨和34.2万吨。多晶硅料扩产得益于下游各制造端的产量扩张。根据中国光伏行业协会数据，2019年，硅片产量134.6GW，电池片产量108.6GW，组件产量98.6GW。上述环节占全球总产量比重分别为90%、77%、72%。</p>\r\n<p>今年，光伏各制造端扩产的步伐仍在加速。中环股份2019年规划单晶硅片总产能56GW，2020年规划单晶硅片总产能85GW；亿晶光电新建年产3GW硅棒硅片项目。</p>\r\n<p>9月15日晚，晶澳科技公告，拟对一体化产能进行扩建，涉及硅片、电池、组件三个环节，预计总投资额103.91亿元。其中1GW拉晶及5GW切片、20GW拉晶及切片合计投资65亿元，剩余39亿用于电池片、组件项目。</p>\r\n<p>9月10日，隆基股份上调2021年对通威的硅片销售数量，由2021年的16亿硅片调整为26亿片。</p>\r\n<p>《每日经济新闻》记者注意到，光伏全产业链扩产之际又逢硅料涨价，各大企业悄然&ldquo;抢货&rdquo;硅料，锁定长单。</p>\r\n<p>8月，隆基股份与亚洲硅业签订94.98亿元多晶硅料采购大单，约定今年9月1日至2025年8月31日合计采购多晶硅料12.48万吨。</p>\r\n<p>9月，上机数控公告，拟2020~2021年向保利协鑫采购原材料多晶硅料1.67万吨，预计采购金额约为15.70亿元。更早之前的8月，上机数控与新疆大全签订20亿元上下的多晶硅料采购大单。</p>\r\n<p>9月，晶澳科技公告称，公司子公司与新特能源达成战略合作，计划于2020年10月至2025年12月期间购买原生多晶硅9.72万吨。参照咨询机构PVInfoLink最新公布的价格估算，预计上述协议合同金额约为91.37亿元。</p>\r\n<p>短则两年，多则五年，各方下手锁定未来五年的多晶硅料，理由只有一个&mdash;&mdash;保上游供应。自2011年多晶硅料一路暴跌以来，下游企业长单锁量的一幕已极其罕见。</p>\r\n<p>永祥股份副总经理禚东举对《每日经济新闻》记者表示：&ldquo;他们（下游客户）的判断比我们还要乐观，对未来的光伏市场充满信心。现在是我们接到订单的量太大，需求量太大，要快速生产产品满足客户需求。&rdquo;</p>\r\n<p>记者在和多位光伏业内人士交流中了解到，光伏急速扩张的装机量，将很大程度上取决于上游硅料的供应量。</p>\r\n<p>硅料扩张步伐是否能跟上陡增的需求？从国内硅料企业的扩产进度看，起码最近两年的新增产能很少。</p>\r\n<p>&nbsp;</p>\r\n<h2><strong>硅料扩产主要在头部企业</strong></h2>\r\n<p>&ldquo;二期项目在筹划中。需要积极推动生产要素匹配、供电线路建设等。&rdquo;袁中华向记者说道，关于内蒙通威二期项目的筹划，公司将基于一期项目的生产工艺情况，进一步做好工艺技术等方面的优化设计。</p>\r\n<figure class=\"image\"><img src=\"https://p3-tt.byteimg.com/origin/pgc-image/SB7vtNz5P2tPQ9?from=pc\" alt=\"光伏涨价博弈步入&ldquo;冷静期&rdquo;：下游豪掷百亿要保供 头部多晶硅企业扩产忙\" /></figure>\r\n<p>展示台的硅片。图片来源：每经记者 胥帅 摄</p>\r\n<p>他还提到了永祥股份的扩产规划：2019年，永祥股份的出货量为8万吨/年，2021年要达到16万吨/年，2023年要达到22万~29万吨/年，&ldquo;现在的行业发展，越来越向龙头企业集中。目前通威的硅料产能8万吨，根据通威的规划，到那个时候将毫无争议的成为行业领头羊！&rdquo;</p>\r\n<p>根据前瞻产业研究院数据，截至2019年底，国内多晶硅企业名义产能超过万吨级别的有&mdash;&mdash;保利协鑫8.5万吨，永祥股份8万吨，新特能源7.2万吨，新疆大全7万吨，东方希望4万吨，亚洲硅业2万吨和内蒙东立1.2万吨等八大厂家，合计超30万吨/年。若按照通威股份的规划，23万吨产能，将占据国内八家大厂总产能的七成。</p>\r\n<p>然而除开通威股份的云南保山项目、永祥新能源（新厂）二期之外，其余大厂2020年的扩产计划较少。</p>\r\n<p>&ldquo;新疆大全准备上科创板，有扩产计划，亚洲硅业有扩产计划，其余似乎就没有看到公开消息。&rdquo;一位电力设备与新能源行业分析师表示。</p>\r\n<p>就在8月中旬，亚洲硅业年产3万吨电子级多晶硅项目一期工程动员大会在西宁举行。亚洲硅业计划分两期建设年产6万吨电子级多晶硅，项目总投资50亿元。</p>\r\n<p>9月11日，新疆大全科创板上市招股书（申报稿）获受理，公司的募投项目之一正是年产35000吨多晶硅项目。根据申报稿内容，该项目总投资为35.1亿元。经测算，本项目投产后预计可实现年均营业收入26.1亿元，年均净利润4.94亿元。</p>\r\n<p>加上已有产能7万吨，这意味着如募投项目投产后，新疆大全的实际产能将达到10.5万吨。新疆大全在招股书中提及，项目建设期为19个月，意味着最终的投产时间可能在2022年。</p>\r\n<p>&ldquo;最近三到五年，韩国OCI、德国瓦克的产能被动压缩，成本缺乏竞争力。改变格局背后，不只是产能和产量规模，还将通过竞争优势支撑改变产业格局。这会形成优中越优的良好循环，中国多晶硅比例在全球也会提升。&rdquo;袁中华表示，多晶硅成本和工艺竞争上，海外企业很难对中国企业构成挑战。</p>\r\n<p>另外一个是成本核算维度，国内企业产能扩张并非想扩就能扩，&ldquo;我们为什么2017年没有扩？&rdquo;袁中华就此反问，这背后是因为成本没有体现出优势，哪家企业扩产厉害，谁就&ldquo;死&rdquo;得快。</p>\r\n<p>受价格约束，降低单位边际成本的扩产行为才更有意义。今年上半年，通威硅料平均生产成本为3.95万元/吨，新产能平均生产成本为3.65万元/吨，基本上是行业最低。在最近两年，无论是从扩产的时间、产能来看，通威股份的动作最快，力度最大。</p>\r\n<p>&ldquo;我们二期项目要努力在一期基础上再降5%成本，甚至10%。要让二期比第一期更具竞争力。&rdquo;永祥股份董事兼首席技术官甘居富对《每日经济新闻》记者表示。</p>\r\n<p>袁中华表示，目前公司的多晶硅技术路线还有很多潜力可以挖掘，&ldquo;我们通过&lsquo;永祥法&rsquo;循环生产，比如现在把蒸汽消耗降到以前的1/10，甚至于最后会变为&lsquo;0&rsquo;蒸汽消耗。&rdquo;</p>\r\n<p>从2007年到现在，多晶硅行业大浪淘沙背后，是极致成本控制&mdash;&mdash;综合电耗从2007年的350KWH/KG降低到2019年的70KWH/KG，降幅高达80%。</p>\r\n<p>全要素成本下降也是光伏产业的必由之路，因为边际成本决定了边际价格。根据可再生能源机构IRENA的数据，2010年~2019年，光伏发电总装机成本下降了约4/5。平价上网年代，最终度电成本下降才能保证光伏发电的竞争优势。所以在2020年4月，全球才会出现1.35美分/KWH的最低中标价格。</p>\r\n<p>一方面是平价上网的低价格，另一方面整个光伏产业链还有向上的空间。正泰新能源总裁陆川在2020第三届中国国际光伏产业高峰论坛上表示，光伏要高质量发展，在产业链上应强调做精做强，而不是更全更大，虽然未来有很多不确定因素，但从历史上的一些典型案例来看，行业发展需要的是全行业的协同智慧。</p>\r\n<p>从资本市场来看，整个光伏板块个股也处于2018年以来的高位。</p>\r\n<p>隆基股份股价一路上涨，刷新新高，市值逼近3000亿元；通威股份股价高位震荡，总市值突破千亿元；晶澳科技股价新高，市值逼近400亿元；晶盛机电股价新高，市值也逼近400亿元&hellip;&hellip;</p>', '/uploads/page/20200921/412d1d0bd387992a7cd19c3b71d8c932.jpg', 1, '[28, 5]', 9, '2020-09-23 17:12:01', 'now', 1, 97, 0, 0, NULL, NULL, 1, 1, '2020-09-21 19:03:03', '2020-09-23 09:12:01');
INSERT INTO `page` VALUES (31, 3, '微软通过Windows搜索推送美国大选信息 全球用户都可以看到', '虽然其他国家的公民其实是不能投票决定未来4年谁将带领美国，但即将到来的美国大选对于全球而言都非常重要，因此，这并不妨碍微软通过Windows 10开始菜单的搜索结果页向全球Windows 10用户推送美国大选信息。', '<p>虽然其他国家的公民其实是不能投票决定未来4年谁将带领美国，但即将到来的美国大选对于全球而言都非常重要，<strong>因此，这并不妨碍微软通过Windows 10开始菜单的搜索结果页向全球Windows 10用户推送美国大选信息。</strong></p>\r\n<p><strong><img style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"../../../uploads/page_content_image/20201009/03c060edd307737ae9c88dfdb46e050b.jpg\" alt=\"\" width=\"1000\" height=\"1405\" /></strong></p>\r\n<p>新的大选横幅现在在Windows10搜索控制台中占据了傲人的位置，取代了之前的COVID-19信息中心链接。</p>\r\n<p>该横幅敦促合资格的Windows 10用户中的选民抓紧注册投票，并通过Bing提供选民登记指引，包括有关登记截止日期和如何检查登记状态的信息。</p>\r\n<p>虽然这些信息可能有点没有针对性，但很明显，拉高选举投票率会带来更好的结果，如果用户不喜欢这个横幅，点击小叉就可以永久关闭。</p>', '/uploads/page/20200921/6b3c0ab71532bb5954d85c85241d3b76.jpg', 1, '[28, 27, 2]', 32, '2020-09-22 01:20:39', 'timing', 1, 58, 0, 0, NULL, NULL, 1, 1, '2020-09-21 19:06:21', '2020-10-28 20:00:05');
COMMIT;

-- ----------------------------
-- Table structure for page_category
-- ----------------------------
DROP TABLE IF EXISTS `page_category`;
CREATE TABLE `page_category` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `value` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `admin_user_id` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='文章类别表';

-- ----------------------------
-- Records of page_category
-- ----------------------------
BEGIN;
INSERT INTO `page_category` VALUES (1, '技术杂文', 1, '2020-08-15 18:14:18', NULL);
INSERT INTO `page_category` VALUES (2, 'Symfony', 1, '2020-08-15 18:14:25', NULL);
INSERT INTO `page_category` VALUES (3, '生活随笔', 1, '2020-08-15 18:14:33', NULL);
INSERT INTO `page_category` VALUES (4, 'Linux', 1, '2020-09-01 13:51:41', NULL);
INSERT INTO `page_category` VALUES (5, 'Docker', 1, '2020-08-21 23:30:26', NULL);
INSERT INTO `page_category` VALUES (6, 'RabbitMQ', 1, '2020-08-21 23:30:45', NULL);
INSERT INTO `page_category` VALUES (10, 'Mysql', 1, '2020-09-01 18:17:09', NULL);
INSERT INTO `page_category` VALUES (15, 'Doctrine', 1, '2020-09-11 17:48:16', NULL);
COMMIT;

-- ----------------------------
-- Table structure for page_comment
-- ----------------------------
DROP TABLE IF EXISTS `page_comment`;
CREATE TABLE `page_comment` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `page_id` int(11) NOT NULL,
  `parent_id` int(11) NOT NULL DEFAULT '0',
  `nickname` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `status` int(11) DEFAULT '0' COMMENT '状态：0未审核，1已审核，2已拒绝',
  `comment` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `ip` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=82 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='文章评论表';

-- ----------------------------
-- Records of page_comment
-- ----------------------------
BEGIN;
INSERT INTO `page_comment` VALUES (1, 1, 0, 'fx488', NULL, 1, '在成为最好linux发行版的大路上越陷越深', '127.0.0.1', '2020-09-02 08:01:15', '2020-09-25 05:17:08');
INSERT INTO `page_comment` VALUES (2, 2, 0, '烽火云烟', NULL, 1, '哪天微软突然说已经基于 Linux 实现 Windows 可执行文件的二进制兼容，下个大版本 Windows 将使用 Linux 内核我都不奇怪。', '127.0.0.1', '2020-09-01 08:01:41', '2020-09-25 05:17:08');
INSERT INTO `page_comment` VALUES (3, 3, 0, '幸运果', NULL, 1, '微软捣乱一流，先把win10 bug解一下吧', '127.0.0.1', '2020-09-03 08:02:09', '2020-09-25 05:17:08');
INSERT INTO `page_comment` VALUES (4, 1, 0, 'tucoo', NULL, 1, '不奇怪，但10年内或者我真写的写不动代码了大概还是看不到这一天吧', '127.0.0.1', '2020-08-05 08:02:45', '2020-09-21 03:00:32');
INSERT INTO `page_comment` VALUES (5, 2, 0, 'eecho', NULL, 1, '为了那一点点性能提升而牺牲兼容性，我觉得没有必要，这就是为什么5年前PHP7支持GCC的PGO，但几乎没多少人编译PHP时会启用PGO优化。', '127.0.0.1', '2020-09-05 08:03:42', '2020-09-21 03:00:32');
INSERT INTO `page_comment` VALUES (6, 2, 2, '983kash起帆', NULL, 1, '这就是为什么5年前PHP7支持GCC的PGO，但几乎没多少人编译PHP时会启', '127.0.0.1', '2020-09-05 15:18:24', '2020-09-21 03:00:32');
INSERT INTO `page_comment` VALUES (7, 2, 2, 'shkshhht001', NULL, 1, '微软捣乱一流，先把win10 bug解一下吧,这就是为什么5年前PHP7支持GCC的PGO，但几乎没多少人编译PHP时会启', '127.0.0.1', '2020-09-05 15:18:35', '2020-09-21 03:00:32');
INSERT INTO `page_comment` VALUES (8, 2, 6, 's＋sf', NULL, 1, '或者我真写的写不动代码了大概还是看不到这一天吧', '127.0.0.1', '2020-09-05 15:19:12', '2020-09-21 03:00:32');
INSERT INTO `page_comment` VALUES (57, 2, 29, 'youhaha', 'admin@info.com', 2, 'hi, 我很喜欢这个主题风格，喜欢能推出更多的主题', '127.0.0.1', '2020-09-05 19:03:28', '2020-09-22 06:28:10');
INSERT INTO `page_comment` VALUES (58, 2, 29, 'gao', '1241321748@qq.com', 2, '希望能聚集symfony爱好者，一起完善gaoblog项目', '127.0.0.1', '2020-09-05 19:13:55', '2020-09-22 06:28:10');
INSERT INTO `page_comment` VALUES (80, 3, 0, '肖虎威', '97902393@qq.com', 2, '666', '127.0.0.1', '2020-09-23 18:37:22', '2020-09-26 02:28:29');
INSERT INTO `page_comment` VALUES (81, 3, 80, 'gao', '1241321748@qq.com', 0, '最是那一低头的温柔，像一朵水莲花不胜凉风的娇羞，道一声珍重，道一声珍重，那一声珍重里有蜜甜的忧愁', '127.0.0.1', '2020-09-23 18:37:51', '2020-09-23 10:38:12');
COMMIT;

-- ----------------------------
-- Table structure for page_tag
-- ----------------------------
DROP TABLE IF EXISTS `page_tag`;
CREATE TABLE `page_tag` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `value` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `admin_user_id` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='文章标签表';

-- ----------------------------
-- Records of page_tag
-- ----------------------------
BEGIN;
INSERT INTO `page_tag` VALUES (1, 'Symfony', 1, '2020-08-15 17:32:08', NULL);
INSERT INTO `page_tag` VALUES (2, 'PHP', 1, '2020-08-15 17:32:08', NULL);
INSERT INTO `page_tag` VALUES (3, 'Redis', 1, '2020-08-15 17:32:08', NULL);
INSERT INTO `page_tag` VALUES (4, 'Docker', 1, '2020-08-15 17:32:08', NULL);
INSERT INTO `page_tag` VALUES (5, 'RabbitMQ', 1, '2020-08-15 17:32:08', NULL);
INSERT INTO `page_tag` VALUES (6, 'Mysql', 1, '2020-08-15 17:32:08', NULL);
INSERT INTO `page_tag` VALUES (10, 'Java', 1, '2020-08-15 20:35:39', NULL);
INSERT INTO `page_tag` VALUES (11, 'Linux', 1, '2020-08-17 05:02:21', NULL);
INSERT INTO `page_tag` VALUES (24, 'Doctrine', 1, '2020-09-01 18:58:53', '2020-09-11 09:47:31');
INSERT INTO `page_tag` VALUES (25, 'Golang', 1, '2020-09-01 18:59:14', '2020-09-01 10:59:21');
INSERT INTO `page_tag` VALUES (27, '生活', 1, '2020-09-21 18:22:12', NULL);
INSERT INTO `page_tag` VALUES (28, '杂七杂八', 1, '2020-09-21 18:22:23', '2020-10-09 17:07:53');
COMMIT;

-- ----------------------------
-- Table structure for setting
-- ----------------------------
DROP TABLE IF EXISTS `setting`;
CREATE TABLE `setting` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `seo_keys` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `seo_description` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `site_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `site_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `introduce` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `avatar` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `image` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `phone` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `address` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `social_qq` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `social_wechat` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `social_weibo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `social_qzone` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `description` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `dashboard_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `is_subscribe` tinyint(1) DEFAULT '1',
  `is_comment` tinyint(1) DEFAULT '0',
  `is_auto_pass_comment` tinyint(1) DEFAULT '0',
  `is_reply` tinyint(1) DEFAULT '1',
  `is_maintenance` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='设置表';

-- ----------------------------
-- Records of setting
-- ----------------------------
BEGIN;
INSERT INTO `setting` VALUES (1, '高,博客,开源,symfony,php,开源博客,php,php 博客,php blog', '高的开源博客, symfony blog', 'GaoBlog', 'http://blog.gaoop.com', '星光不问赶路人，时光不负有心人。这个世界上真的有人在过着你想要的生活。而那些人大都曾隐忍过你尚未经历的挫折。', '一个藤上三个瓜', '/uploads/setting/20200906/70646e23c608808ecdde4719f7836614.jpg', '/uploads/page/20200908/25ade1fee0c9bef3c04ed9129cf8f8a8.jpg', '17756573476', 'gaoblog@gaoop.com', '安徽省合肥市蜀山区幸福小区2栋1单元302室', '1241321748', 'gaooop', '一个藤上三个瓜', 'https://github.com/gaojinsheng', '我们总以为阳光是来自于太阳，可是在我们心里幽暗的时候，再灿烂的阳光也不能把我们拉出阴影。其实，阳光不只是来自于太阳，也来自我们的心。只要我们心里有光，就会感应到世界的光彩；只要我们心里有光，就能与有缘有情的人相互照亮；只要我们心里有光，即便在最寒冷、阴霾的日子，也能感受到温暖！\r\n<br /><br />\r\n人总是在遭遇一次重创之后，才会幡然醒悟，重新认识自己的坚强和隐忍。所以，无论你正在遭遇什么磨难，都不要一味抱怨上苍不公平，甚至从此一蹶不振。人生没有过不去的坎，只有过不去的人。', 'workbench', 0, 1, 0, 0, 0);
COMMIT;

-- ----------------------------
-- Table structure for subscribe
-- ----------------------------
DROP TABLE IF EXISTS `subscribe`;
CREATE TABLE `subscribe` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `ip` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `status` tinyint(1) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订阅表';

-- ----------------------------
-- Records of subscribe
-- ----------------------------
BEGIN;
INSERT INTO `subscribe` VALUES (7, '1241321748@qq.com', '127.0.0.1', NULL, '2020-09-03 01:04:27', NULL);
INSERT INTO `subscribe` VALUES (9, 'gaoblog@yeah.net', '127.0.0.1', NULL, '2020-09-04 04:12:22', '2020-09-04 23:18:38');
INSERT INTO `subscribe` VALUES (10, '1920377269@qq.com', '127.0.0.1', NULL, '2020-09-05 14:57:43', NULL);
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;
